Esta es una pregunta de tarea. Dicen que toma O(logN + logM)
dónde N
y M
son las longitudes de las matrices.
Nombramos las matrices a
y b
. Obviamente podemos ignorar todo a[i]
y b[i]
donde i> k.
Primero comparemos a[k/2]
y b[k/2]
. Vamos b[k/2]
> a[k/2]
. Por tanto, podemos descartar también todosb[i]
, donde i> k / 2.
Ahora tenemos todo a[i]
, donde i <ky todob[i]
, donde i <k / 2 para encontrar la respuesta.
¿Cuál es el próximo paso?
arrays
algorithm
binary-search
Miguel
fuente
fuente
O(logN + logM)
refiere solo al tiempo que lleva encontrar el k-ésimo elemento? ¿Se puede realizar un procesamiento previo al sindicato de antemano?Respuestas:
Lo tienes, ¡sigue adelante! Y cuidado con los índices ...
Para simplificar un poco, asumiré que N y M son> k, por lo que la complejidad aquí es O (log k), que es O (log N + log M).
Pseudocódigo:
Para la demostración, puede usar el invariante de bucle i + j = k, pero no haré toda su tarea :)
fuente
Espero no estar respondiendo a su tarea ya que ha pasado más de un año desde que se hizo esta pregunta. Aquí hay una solución recursiva de cola que tomará log (len (a) + len (b)) tiempo.
Supuesto: las entradas son correctas. es decir, k está en el rango [0, len (a) + len (b)]
Casos base:
Pasos de reducción:
a
+ el índice medio deb
es menor quek
a
es mayor que el elemento medio deb
, podemos ignorar la primera mitad deb
, ajustark
.a
, ajustek
.k
es menor que la suma de los índices medios dea
yb
:a
es mayor que el elemento medio deb
, podemos ignorar con seguridad la segunda mitad dea
b
Código:
Tenga en cuenta que mi solución es crear nuevas copias de matrices más pequeñas en cada llamada, esto se puede eliminar fácilmente pasando solo índices de inicio y finalización en las matrices originales.
fuente
kthlargest()
devuelve?(k+1)
-th elementos más pequeños, por ejemplo,1
es el segundo elemento más pequeño en0,1,2,3
, es decir, su función devuelvesorted(a+b)[k]
.Mucha gente respondió a esta pregunta del "k-ésimo elemento más pequeño de dos arreglos ordenados", pero por lo general solo con ideas generales, no con un código de trabajo claro o un análisis de condiciones de frontera.
Aquí me gustaría desarrollarlo cuidadosamente con la forma en que fui para ayudar a algunos novatos a comprender, con mi código Java que funciona correctamente.
A1
yA2
son dos matrices ascendentes ordenadas, consize1
ysize2
como longitud respectivamente. Necesitamos encontrar el k-ésimo elemento más pequeño de la unión de esas dos matrices. Aquí asumimos razonablemente que(k > 0 && k <= size1 + size2)
, lo que implica queA1
yA2
no puede estar vacío a la vez.Primero, abordemos esta pregunta con un algoritmo lento de O (k). El método consiste en comparar el primer elemento de la matriz
A1[0]
yA2[0]
. Toma el más pequeño, diA1[0]
en nuestro bolsillo. Luego compareA1[1]
conA2[0]
, y así sucesivamente. Repite esta acción hasta que nuestro bolsillo alcancek
elementos. Muy importante: En el primer paso, solo podemos comprometernosA1[0]
en nuestro bolsillo. ¡NO podemos incluir ni excluirA2[0]
!El siguiente código O (k) le da un elemento antes de la respuesta correcta. Aquí lo uso para mostrar mi idea y analizar la condición de contorno. Tengo el código correcto después de este:
La idea más poderosa es que en cada ciclo, siempre usamos el enfoque del caso base. Después de comprometernos con el elemento más pequeño actual, nos acercamos un paso más al objetivo: el k-ésimo elemento más pequeño. ¡Nunca salte al medio y se confunda y se pierda!
Al observar el caso base del código anterior
k == 1, k == size1+size2
, y combinar con esoA1
yA2
no pueden ser ambos vacía. Podemos convertir la lógica en un estilo más conciso a continuación.Aquí hay un código de trabajo lento pero correcto:
Ahora podemos probar un algoritmo más rápido que se ejecuta en O (log k). Del mismo modo, compare
A1[k/2]
conA2[k/2]
; siA1[k/2]
es más pequeño, entonces todos los elementos desdeA1[0]
hastaA1[k/2]
deberían estar en nuestro bolsillo. La idea es no solo comprometerse con un elemento en cada ciclo; el primer paso contienek/2
elementos. Nuevamente, NO podemos incluir ni excluirA2[0]
deA2[k/2]
todos modos. Entonces, en el primer paso, no podemos ir más quek/2
elementos. Para el segundo paso, no podemos ir más quek/4
elementos ...Después de cada paso, nos acercamos mucho más al k-ésimo elemento. Al mismo tiempo, cada paso se hace cada vez más pequeño, hasta que llegamos
(step == 1)
, que es(k-1 == index1+index2)
. Entonces podemos volver a referirnos al caso base simple y poderoso.Aquí está el código de trabajo correcto:
Algunas personas pueden preocuparse ¿qué
(index1+index2)
pasa si saltan sobre k-1? ¿Podríamos perder el caso base?(k-1 == index1+index2)
? Eso es imposible. Puedes sumar 0.5 + 0.25 + 0.125 ..., y nunca irás más allá de 1.Por supuesto, es muy fácil convertir el código anterior en un algoritmo recursivo:
Espero que el análisis anterior y el código Java puedan ayudarlo a comprender. ¡Pero nunca copie mi código como tarea! Salud ;)
fuente
else if (A1[size1 - 1].compareTo(A2[size2 - 1]) < 0)
lugar deelse if (A1[size1 - 1].compareTo(A2[size2 - 1]) > 0)
? (En el código kthSmallestSlowWithFault)Aquí hay una versión iterativa de C ++ de la solución de @ lambdapilgrim (vea la explicación del algoritmo allí):
Funciona para todos los
0 <= n < (size(a) + size(b))
índices y tieneO(log(size(a)) + log(size(b)))
complejidad.Ejemplo
fuente
Mi intento por los primeros k números, k-ésimo número en 2 matrices ordenadas y en n matrices ordenadas:
El código completo con las utilidades de depuración se puede encontrar en: https://github.com/brainclone/teasers/tree/master/kth
fuente
Aquí está mi código basado en la solución de Jules Olleon:
fuente
Aquí está mi implementación en C, puede consultar las explicaciones de @Jules Olléon para el algoritmo: la idea detrás del algoritmo es que mantenemos i + j = k, y encontramos tales i y j de modo que a [i-1] <b [j-1] <a [i] (o al revés). Ahora, dado que hay i elementos en 'a' más pequeños que b [j-1], y j-1 elementos en 'b' más pequeños que b [j-1], b [j-1] es el i + j-1 + 1 = k-ésimo elemento más pequeño. Para encontrar tal i, j, el algoritmo realiza una búsqueda dicotómica en las matrices.
fuente
Esta es mi solución. El código C ++ imprime el k-ésimo valor más pequeño así como el número de iteraciones para obtener el k-ésimo valor más pequeño usando un bucle, que en mi opinión está en el orden de log (k). Sin embargo, el código requiere que k sea menor que la longitud de la primera matriz, lo cual es una limitación.
fuente
El primer pseudocódigo proporcionado anteriormente no funciona para muchos valores. Por ejemplo, aquí hay dos matrices. int [] a = {1, 5, 6, 8, 9, 11, 15, 17, 19}; int [] b = {4, 7, 8, 13, 15, 18, 20, 24, 26};
No funcionó para k = 3 y k = 9 en él. Tengo otra solucion Se da a continuación.
Pero ... tampoco funciona para k = 5. Existe esta captura par / impar de k que no deja que sea simple.
fuente
fuente
Aquí está la solución mía en java. Intentará optimizarlo aún más
Esto está inspirado en Algo en un maravilloso video de youtube
fuente
Enlace a la complejidad del código (log (n) + log (m))
Enlace al código (log (n) * log (m))
Implementación de la solución (log (n) + log (m))
Me gustaría agregar mi explicación al problema. Este es un problema clásico en el que tenemos que utilizar el hecho de que las dos matrices están ordenadas. se nos han dado dos matrices ordenadas arr1 de tamaño sz1 y arr2 de tamaño sz2
a) Supongamos que si
Comprobando si k es válido
entonces no podemos encontrar el k-ésimo elemento más pequeño en la unión de ambas matrices ordenadas ryt Entonces devuelve datos no válidos. b) Ahora, si la condición anterior es falsa y tenemos un valor válido y factible de k,
Gestión de casos periféricos
Agregaremos tanto las matrices por valores -infinito al principio como valores + infinito al final para cubrir los casos extremos de k = 1,2 y k = (sz1 + sz2-1), (sz1 + sz2), etc.
Algoritmo principal
Ahora, haremos una búsqueda binaria en arr1. Haremos una búsqueda binaria en arr1 buscando un índice i, startIndex <= i <= endIndex
tal que si encontramos el índice j correspondiente en arr2 usando la restricción {(i + j) = k}, entonces si
Como sabemos que el k-ésimo elemento más pequeño tiene (k-1) elementos más pequeños que él en la unión de ambas matrices ryt? Entonces,
En el caso 1 , lo que hicimos, nos aseguramos de que haya un total de (k-1) elementos más pequeños en arr1 [i] porque los elementos más pequeños que arr1 [i] en la matriz arr1 son i-1 en número de lo que sabemos (arr2 [ j-1] <arr1 [i] <arr2 [j]) y el número de elementos menores que arr1 [i] en arr2 es j-1 porque j se encuentra usando (i-1) + (j-1) = (k -1) Entonces el k-ésimo elemento más pequeño será arr1 [i]
Pero la respuesta no siempre puede provenir de la primera matriz, es decir, arr1, por lo que verificamos el caso2, que también satisface de manera similar al caso 1 porque (i-1) + (j-1) = (k-1). Ahora, si tenemos (arr1 [i-1] <arr2 [j] <arr1 [i]) tenemos un total de k-1 elementos más pequeños que arr2 [j] en unión de ambos arreglos, por lo que es el k-ésimo elemento más pequeño.
en case3 , para formar a cualquiera de caso 1 o el caso 2, es necesario para incrementar i y j se encontrará según el uso de restricción {(i + j) = k} es decir, en la búsqueda binaria movimiento para parte derecha es decir, hacer startIndex = middleIndex
En el caso 4 , para formarlo en cualquiera de los casos 1 o 2, necesitamos disminuir i y j se encontrarán de acuerdo con la restricción {(i + j) = k} es decir, en la búsqueda binaria, mover a la parte izquierda, es decir, hacer endIndex = middleIndex .
Ahora, ¿cómo decidir startIndex y endIndex al comienzo de la búsqueda binaria sobre arr1 con startindex = 1 y endIndex = ??. Tenemos que decidir.
Porque si k es mayor que el tamaño de la primera matriz, es posible que tengamos que hacer una búsqueda binaria en toda la matriz arr1; de lo contrario, solo necesitamos tomar los primeros k elementos porque sz1-k elementos nunca pueden contribuir en el cálculo de la k-ésima menor.
CÓDIGO mostrado a continuación
Para Solución de complejidad (log (n) * log (m))
Simplemente no aproveché la ventaja del hecho de que para cada i, el j se puede encontrar usando la restricción {(i-1) + (j-1) = (k-1)} Entonces, para cada ii se aplicó una búsqueda binaria en la segunda matriz para encontrar j tal que arr2 [j] <= arr1 [i]. Entonces esta solución se puede optimizar aún más
fuente
Básicamente, a través de este enfoque, puede descartar k / 2 elementos en cada paso. La K cambiará recursivamente de k => k / 2 => k / 4 => ... hasta que llegue a 1. Entonces, la complejidad del tiempo es O (logk)
En k = 1, obtenemos la más baja de las dos matrices.
El siguiente código está en JAVA. Tenga en cuenta que estamos restando 1 (-1) en el código de los índices porque el índice de la matriz de Java comienza en 0 y no en 1, por ejemplo. k = 3 está representado por el elemento en el segundo índice de una matriz.
fuente
La complejidad del tiempo es O (log (min (n, m)))
fuente
La mayoría de las respuestas que encontré aquí se centran en ambas matrices. si bien es bueno, pero es más difícil de implementar, ya que hay muchos casos extremos de los que debemos ocuparnos. Además de que la mayoría de las implementaciones son recursivas, lo que agrega la complejidad espacial de la pila de recursividad. Entonces, en lugar de enfocarme en ambas matrices, decidí enfocarme solo en la matriz más pequeña y hacer la búsqueda binaria solo en la matriz más pequeña y ajustar el puntero para la segunda matriz en función del valor del puntero en la primera matriz. Mediante la siguiente aplicación, tenemos la complejidad de
O(log(min(n,m))
laO(1)
complejidad del espacio.Tenemos un rango de
[low, high]
for arraya
y estrechamos este rango a medida que avanzamos en el algoritmo.sizeA
muestra cuántos elementos de losk
elementos son de la matriza
y se deriva del valor delow
yhigh
.sizeB
es la misma definición excepto que calculamos el valor de tal manera quesizeA+sizeB=k
. El basado en los valores en esos dos bordes concluye que tenemos que extendernos hacia el lado derecho en una matriza
o encogernos hacia el lado izquierdo. si nos limitamos en la misma posición que significa que hemos encontrado la solución y se remitirá el máximo de los valores en la posición desizeA-1
partira
ysizeB-1
desdeb
.fuente
Verifique este código.
fuente
Debajo del código C # para encontrar el k-ésimo elemento más pequeño en la unión de dos matrices ordenadas. Complejidad de tiempo: O (logk)
fuente
midA
partir deendA
ifk < n
. Compruebe si hay matrices cortas, comenzando conreturn B[startB + k - 1];
.)