Cómo encontrar un elemento duplicado en una matriz con una complejidad temporal menor que O (n ^ 2) y una complejidad espacial de O (1)

Antes de considerar cualquier cosa, debe hacer algunas preguntas más. Algunos puedo pensar en la parte superior de mi cabeza:

  1. ¿Es que estás buscando un elemento AN? Es decir, ¿tiene algún valor y necesita verificar si ocurre más de una vez en la matriz? De su pregunta no está claro si esto es lo que se pregunta o si necesita encontrar CUALQUIER elemento que ocurra más de una vez. Si este es el caso, es solo una búsqueda lineal: solo se detiene una vez que ha encontrado el valor dos veces (O (N) tiempo y O (1) espacio).
  2. ¿La matriz está ordenada o sus valores están organizados en algún orden? En este caso, solo necesitaría pasar de principio a fin, verificando si los elementos consecutivos son iguales, es decir, O (N) tiempo y O (1) espacio.
  3. Viendo que la matriz solo contiene valores entre 1 y N … ¿hay algún límite para N? Esto es muy probable ya que una matriz tiende a imponer algunos límites en su longitud, especialmente si su indexación está utilizando algún valor entero fijo. Todo lo que significa es un campo de bits lo suficientemente largo como para contener todos los valores posibles de la longitud de una matriz, es decir, un campo de bits de longitud constante (un tamaño O (1)) y una búsqueda de tiempo O (N) en el peor de los casos. Por ejemplo, el peor de los casos generales: si el índice en la matriz es un 32 con signo int, usted “sabe” que no puede haber un N mayor que 2,147,483,648 … lo que significa que necesita un campo de bits de 268,435,456 bytes de longitud (256MB), independientemente de lo que sea N. Si hay un límite menor para los tamaños de matriz, entonces esta longitud del campo de bits también se reduce.

Arriba hay algunas preguntas que hacer antes de considerar cualquier cosa, ya que sus respuestas permitirían mejorar considerablemente las velocidades posibles.

De lo contrario (si las tres respuestas son negativas) se convierte en:

  1. El peor de los casos fuerza bruta O (N ^ 2) tiempo + O (1) espacio (que la pregunta parece tratar de evitar)
  2. O algo así como un recuento temporal de hash map / radix (es decir, O (N) tiempo y O (N) espacio); nuevamente, la complejidad del espacio limitante de la pregunta para no permitir esto.
  3. O algo así como la idea de encontrar el ciclo según la respuesta de Christopher. Que estrictamente va a ser un tiempo O (M + S ^ 2), donde S es la distancia entre los duplicados y M la posición del primero, aunque no se ve exactamente afectado por N.

Si esto fue algo así como una pregunta de entrevista y usted acaba de responder con algo como la idea de búsqueda de ciclo, solo le daría el 50% por su respuesta.

Para las entrevistas, en realidad es un intento de averiguar cómo piensas en lugar de saber la respuesta, es decir, me gustaría saber si puedes ver problemas en la pregunta planteada y quieres claridad para que puedas convertirla en la mejor solución posible .

La razón por la que solo daría el 50% para una respuesta “correcta” sin más preguntas es que significa que tiendes a asumir cosas, lo que generalmente es una muy mala señal para un programador. Al menos sabes “cómo”, por lo que no es 0%.

Esto se puede hacer en O (n) tiempo.

Imagine que se trata de una matriz de punteros, donde el primer índice es cero: por ejemplo, si un [0] es 5, eso corresponde a una flecha que apunta de la celda 0 a la celda 5. Un elemento duplicado corresponde a varias flechas que apuntan a la misma celda.

¿Qué sucede si comienzas desde la posición 0 y sigues las flechas? Bueno, no puedes seguir viendo nuevas células para siempre; eventualmente, debes repetir una celda por primera vez. Pero la posición 0 no tiene flechas entrantes, ya que todos los enteros son de 1 a n. Entonces, esta primera repetición debe ocurrir en otro lugar … en otro lugar con al menos dos flechas entrantes, ya que de lo contrario el paso anterior también habría sido una repetición.

Sabiendo esto, ¿cómo encuentras * qué * celda en la ruta tiene múltiples flechas entrantes? Comience con el clásico algoritmo de búsqueda de ciclo “tortuga y liebre” de Floyd (Detección de ciclos – Wikipedia): haga que una “tortuga” dé un paso a la vez y una “liebre” tome dos pasos a la vez desde la posición 0, hasta que se encuentren nuevamente ; entonces estarás en algún lugar del ciclo principal.

Suponga que la tortuga dio S pasos antes de reencontrarse con la liebre en la posición M (entonces la liebre ha tomado 2S pasos). Ahora podemos terminar el trabajo comenzando una segunda tortuga en la posición 0 y haciendo que la primera tortuga continúe desde la posición M (a la liebre se le puede dar un descanso). Sabemos que las dos tortugas se encontrarán dentro de la mayoría de los pasos S (ya que, en ese punto, la primera tortuga habrá tomado exactamente 2 pasos de distancia de la posición 0, y la segunda tortuga habrá tomado exactamente los pasos S) … y también sabemos que la primera vez que se encuentren, habrán venido de diferentes posiciones.

Podemos resolver para cada bit en la representación binaria del número repetido individualmente.

Para cada bit acceda a todos los elementos de la matriz y vea el número de veces que se establece el bit. Ahora en el rango de 1 a N, encuentre cuántas veces se establece el bit.

Si su matriz tiene el bit establecido más veces que el rango [1, N], entonces este bit se establece en el número de repetición, de lo contrario no.

Complejidad de la memoria – O (1)

Complejidad de tiempo – O (N log N)

Además, las operaciones bit a bit son bastante más rápidas que las operaciones normales

La matriz contiene n + 1 enteros y todos los enteros están dentro de 1 a n inclusive.

La suma de todos los elementos en la matriz, calculada en O (1) tiempo, sería [matemática] (1 + n) n / 2 + k [/ matemática], donde k es el número duplicado. Para encontrar el duplicado, todo lo que necesita hacer es sumar todos los elementos en la matriz y restar la suma de 1 a n de la suma.

Esto se puede hacer yendo a través de la matriz una vez O (n) y usando 1 espacio adicional para almacenar la suma, también conocida como O (1) complejidad del espacio.

El código lo explica todo. Si no, lea primero la respuesta de Ivan Appel.

Solución de clase pública {
public int findDuplicate (int [] nums) {
int left = 0, right = nums.length – 1;

while (izquierda int mid = (izquierda + derecha) / 2;
int count = numSmaller (nums, mid);

if (cuenta> mediados) {
derecho = medio;
} más {
izquierda = medio + 1;
}
}

volver a la izquierda;
}

private int numSmaller (int [] nums, int mid) {
int resultado = 0;

para (int num: nums) {
if (num <= mid) {
resultado ++;
}
}

resultado de retorno;
}
}

La idea aproximada de un algoritmo es: elegir k = ceil(n / 2 ) y recorrer una matriz contando cuántos elementos son (A) menores que / (B) mayores que / (C) iguales a k. Si A es más que k – 1, significa que el elemento duplicado está dentro del rango [1..k-1]. Si B es más que n – k, significa que el elemento duplicado está dentro del rango [k + 1..n]. De lo contrario, C tiene más de uno, lo que significa que k es su criminal.

Acortando iterativamente el rango de esta manera, puede encontrar el elemento en O (n log n) tiempo y memoria constante.

¿No es solo una clasificación rápida en el primer pase? Compare primero a último, si primero <último, incremente primero. Si primero = último, encontró una salida duplicada, de lo contrario si primero> último, intercambie (a través de la posición extra 1, no físicamente) y compare de la otra manera. Todo a la derecha cuando las dos posiciones se encuentran es mayor que, a la izquierda, menor que y si obtiene algún igual, salga e imprima. ¿O me estoy perdiendo algo?

More Interesting

¿Qué tipo de preguntas se hacen en la sección de programación de Amdocs (que consta de 7 preguntas de codificación) en la primera ronda de aptitud?

¿Qué tan difíciles son las entrevistas con los ingenieros de software de Bloomberg en comparación con otras compañías tecnológicas como Google, Facebook, etc.?

Cómo prepararse para una entrevista de trabajo de ingeniería de software en muy poco tiempo (tal vez 1 mes)

¿Cuál es su opinión sobre CoderPad?

¿Cuánto tiempo pasaste preparándote para las entrevistas de Google? ¿Todos los que se metieron en Facebook, Google, etc. realmente son tan buenos para resolver o entender cada algoritmo o problema clásico?

¿Cómo debo prepararme para las entrevistas de codificación en el campus?

¿Puedo usar el enfoque de fuerza bruta para resolver preguntas de algoritmos en la entrevista técnica?

¿Cómo es dar una entrevista de codificación?

¿Cuáles son algunas de las preguntas de entrevista no estándar que se hacen actualmente en las empresas / escuelas B?

¿Cómo sé si estoy listo para programar un trabajo (y una entrevista) en Google?

¿Está predispuesto Facebook hacia los candidatos a entrevistas que son los mejores clasificados en las competencias de programación en línea?

¿Qué tipo de preguntas se hacen en la entrevista para la admisión a AFMC Pune?

¿Cómo es la entrevista en persona en Google?

¿Cuál es el contenido teórico de información de las monedas y el acertijo de escala?

Después de su entrevista de programación en una computadora portátil, ¿el entrevistador intenta compilar / ejecutar el código?