La brillante respuesta de caf imprime cada número que aparece k veces en la matriz k-1 veces. Ese es un comportamiento útil, pero la pregunta podría decirse que cada duplicado se imprima una sola vez, y alude a la posibilidad de hacerlo sin soplar los límites de tiempo lineal / espacio constante. Esto se puede hacer reemplazando su segundo bucle con el siguiente pseudocódigo:
for (i = 0; i < N; ++i) {
if (A[i] != i && A[A[i]] == A[i]) {
print A[i];
A[A[i]] = i;
}
}
Esto explota la propiedad de que después de que se ejecuta el primer ciclo, si algún valor maparece más de una vez, se garantiza que uno de esos aspectos esté en la posición correcta, es decir A[m]. Si tenemos cuidado, podemos usar esa ubicación de "hogar" para almacenar información sobre si todavía se han impreso o no duplicados.
En la versión de caf, a medida que avanzábamos por la matriz, A[i] != iimplicaba que A[i]era un duplicado. En mi versión, confío en un invariante ligeramente diferente: eso A[i] != i && A[A[i]] == A[i]implica que A[i]es un duplicado que no hemos visto antes . (Si deja caer la parte "que no hemos visto antes", el resto puede verse implicado por la verdad de invariante de caf, y la garantía de que todos los duplicados tienen alguna copia en la ubicación de una casa). Esta propiedad se mantiene en al principio (después de que finaliza el 1er bucle de caf) y muestro a continuación que se mantiene después de cada paso.
A medida que avanzamos por la matriz, el éxito por A[i] != iparte de la prueba implica que A[i] podría ser un duplicado que no se haya visto antes. Si no lo hemos visto antes, entonces esperamos que A[i]la ubicación de la casa se señale a sí misma, eso es lo que se prueba en la segunda mitad de la ifcondición. Si ese es el caso, lo imprimimos y modificamos la ubicación de inicio para volver a este primer duplicado encontrado, creando un "ciclo" de 2 pasos.
Para ver que esta operación no altera nuestra invariante, supongamos m = A[i]que una posición particular es isatisfactoria A[i] != i && A[A[i]] == A[i]. Es obvio que el cambio que hacemos ( A[A[i]] = i) funcionará para evitar que se produzcan mduplicados otros sucesos ajenos al hogar ifal hacer que falle la segunda mitad de sus condiciones, pero ¿funcionará cuando illegue a la ubicación del hogar m? Sí, porque ahora, a pesar de que en este nuevo inos encontramos con que la primera mitad de la ifcondición A[i] != ies verdadera, la segunda mitad prueba si la ubicación a la que apunta es una ubicación de origen y descubre que no lo es. En esta situación, ya no sabemos si el valor duplicado fue mo no A[m], pero sabemos que de cualquier manera,ya se ha informado , porque se garantiza que estos 2 ciclos no aparecerán en el resultado del primer bucle de caf. (Tenga en cuenta que si m != A[m]entonces exactamente uno de my A[m]ocurre más de una vez, y el otro no ocurre en absoluto).
a[a[i]], y la restricción de espacio O (1) sugiere que laswap()operación es clave.