dificultad para resolver un código en O(logn)
Frecuentes
Visto 302 veces
7
Escribí una función que obtiene como entrada una lista de enteros únicos en orden (de pequeño a grande). Se supone que debo encontrar en la lista un índice que coincida con el valor del índice. por ejemplo, si L[2]==2 la salida es verdadera. así que después de hacer eso en complejidad O (logn) ahora quiero encontrar cuántos índices se comportan así en la lista dada con la misma complejidad O (logn). estoy cargando mi primer código que hace la primera parte y el segundo código con el que necesito ayuda:
def steady_state(L):
lower= 0
upper= len(L) -1
while lower<=upper:
middle_i= (upper+ lower)//2
if L[middle_i]== middle_i:
return middle_i
elif L[middle_i]>middle_i:
upper= middle_i-1
else:
lower= middle_i +1
return None
def cnt_steady_states(L):
lower= 0
upper= len(L) -1
a=b=steady_state(L)
if steady_state(L)== None:
return 0
else:
cnt=1
while True:
if L[upper] == upper and a<=upper:
cnt+= upper-a
upper= a
if L[lower]== lower and b>=lower:
cnt+= b- lower
lower = b
3 Respuestas
2
No es posible con las restricciones que has dado todavía. La mejor complejidad que teóricamente puede lograr es O(n).
O() asume el peor de los casos (solo una definición, podría eliminar esa parte). Y en el peor de los casos lo harás siempre hay que mirar cada item para verificar que sea igual a su índice.
El caso cambia si tiene más restricciones (por ejemplo, los números son todos enteros y ninguno puede aparecer más de una vez, es decir, no hay dos números consecutivos iguales). ¿Quizás este es el caso?
EDIT:
Después de escuchar que, de hecho, se aplican mis restricciones supuestas (es decir, solo enteros que aparecen una vez), ahora propongo este enfoque: puede asumir con seguridad que solo puede tener exactamente un rango continuo donde se encuentran todas las entradas coincidentes. Es decir. solo necesita encontrar un límite inferior y un límite superior. El resultado deseado será entonces el tamaño de ese rango.
Cada límite se puede encontrar con seguridad utilizando una búsqueda binaria, de la cual cada uno tiene O(Iniciar sesión n).
def binsearch(field, lower=True, a=0, b=None):
if b is None:
b = len(field)
while a + 1 < b:
c = (a + b) / 2
if lower:
if field[c] < c:
a = c
else:
b = c
else: # search for upper bound
if field[c] > c:
b = c
else:
a = c
return b if lower else a
def indexMatchCount(field):
upper = binsearch(field, lower=False)
lower = binsearch(field, b=upper+1)
return upper - lower + 1
Esto lo usé para probar:
field = list({ random.randint(-10, 30) for i in range(30) })
field.sort()
upper = binsearch(field, lower=False)
lower = binsearch(field, b=upper+1)
for i, f in enumerate(field):
print lower <= i <= upper, i == f, i, f
respondido 25 nov., 13:10
si, olvidé mencionar eso. todos los números son enteros y aparecen solo una vez - user2751595
Se agregó una solución descriptiva para su problema mediante el uso de dos búsquedas binarias para los límites del rango en el que todos los campos tienen el valor de su índice. - Alfa
1
Suponiendo que los enteros negativos están bien:
Creo que la clave es que si obtiene un valor menor que su índice, sabe que todos los índices a la izquierda tampoco coinciden con su valor (ya que los números enteros son estrictamente crecientes). Además, una vez que obtiene un índice cuyo valor es mayor que el índice, todo lo que está a la derecha es incorrecto (por la misma razón). Luego puede hacer un algoritmo de divide y vencerás como lo hiciste en el primer caso. Algo del estilo de:
check middle index:
if equal:
count = count + 1
check both halves, minus this index
elif value > index:
check left side (lower to index)
elif index > value:
check right side (index to upper)
En el peor de los casos (cada índice coincide con el valor), aún tenemos que verificar cada índice.
Si los números enteros no son negativos, entonces sabes aún más. Ahora también sabe que si un índice coincide con el valor, todos los índices a la izquierda también deben coincidir con el valor (¿por qué?). Por lo tanto, obtienes:
check middle index:
if equal:
count = count + indices to the left (index-lower)
check the right side (index to upper)
elif value > index:
check left side (lower to index)
elif index > value:
##Can't happen in this case
Ahora nuestro peor de los casos ha mejorado significativamente. En lugar de encontrar un índice que coincida y no obtener ninguna información nueva de él, obtenemos una tonelada de información cuando encontramos uno que coincide, y ahora sabemos que la mitad de los índices coinciden.
respondido 22 nov., 13:18
1
Si "todos los números son enteros y aparecen solo una vez", simplemente puede hacer una búsqueda binaria del primer par de números donde L[i]==i && L[i+1]!=i+1
.
Para permitir enteros negativos, compruebe si L[0]<0
, y si es así, busque entre 1..N para:
i>0 && L[i]==i && L[i-1]!=i-1
. Luego realice la búsqueda anterior entre i y N.
respondido 22 nov., 13:18
Si los números enteros pueden ser negativos, aún no sabe qué índices menores que i coinciden con su valor. - hankd
Además, ¿quisiste decir L[i+1] != i+1 en la segunda parte? Porque L[i] == i siempre implica L[i+1] != i. - hankd
buena captura en el i+1
. Si los números enteros pueden ser negativos, la prueba se invierte. Edición. - AShelly
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas python algorithm or haz tu propia pregunta.
¿Pueden estos enteros ser negativos? - hankd