Dada una lista enlazada circular, ¿cómo encuentro la secuencia más larga de nodos de valor no repetido?

Idea básica

Para cada posición inicial, calcule qué tan lejos podemos llegar sin repetir un valor.

Para una sola posición inicial, esto es fácil de hacer. Avance desde la posición inicial, verificando cada valor recién encontrado con una tabla hash que contenga todos los valores encontrados anteriormente. Detente cuando alcances tu punto de partida original o un nodo que sería un duplicado de algo que has visto antes, y registra cuántos nodos visitaste antes de detenerte.

Este procedimiento lleva tiempo O (N) si hay N nodos en la lista, suponiendo que las operaciones de la tabla hash se ejecuten en O (1), porque si un duplicado no lo detiene antes, se detendrá después de visitar N nodos (y hacer N búsquedas de tablas hash y N inserciones de tablas hash).

Obtenemos la respuesta final al ver qué nodo inicial visitamos la mayoría de los nodos antes de detenernos. Aquí hay un problema: no sabemos qué nodo inicial deberíamos usar, por lo que si los probamos todos, pasaremos tiempo O (N) para cada una de las N posibles posiciones iniciales, haciendo que el algoritmo general [matemático] O ( N ^ 2) [/ matemáticas].


Optimizando la solución

Una cosa que es muy notable es que si ya ejecutó el procedimiento comenzando en el primer nodo y visitó K nodos antes de obtener un duplicado, cuando lo ejecute comenzando desde el segundo nodo, visitará, como mínimo, los nodos 2 a K. En esos nodos, estás repitiendo exactamente el mismo trabajo. Tal vez después de llegar al nodo K-th, vaya a visitar algunos nodos adicionales, pero hasta que llegue al nodo K-th, simplemente está duplicando su trabajo de antes.

En base a esto, tenemos la idea de no volver a ejecutar el procedimiento desde cero para cada posible punto de partida. Si cuando comenzamos en el nodo 1 llegamos al nodo K (y el nodo K era un duplicado), entonces simularemos pasar de los nodos 2 a K en un solo paso simplemente eliminando el valor del nodo 1 de la tabla hash del nodo valores (en lugar de restablecer la tabla hash y volver a hacer el recorrido, como antes).

Una vez que la tabla hash corresponde a un recorrido transversal que comienza en el nodo 2, vemos si ahora podemos tomar el nodo K sin que sea un duplicado (esto sucederá si el nodo 1 y el nodo K tienen el mismo valor), y si es así, intentamos expandir la ventana tanto como podamos con nodos más allá de eso. (Si el nodo K sigue siendo un duplicado, nos detenemos en el nodo K una vez más.) De cualquier manera, registramos la longitud de secuencia libre de duplicados comenzando en el nodo 2, e intentamos el siguiente punto de partida (con una reutilización similar de la tabla hash )


Análisis de la solución optimizada

Notamos que hay N posibles puntos de partida, y la “ventana libre de duplicados” de cada punto de partida no se extiende más de N elementos. Eso significa que el final de la ventana atravesará no más de 2N elementos en total a lo largo del algoritmo. En total, eliminamos como máximo N valores de la tabla hash, insertamos como máximo 2N valores y buscamos como máximo 2N valores. El otro trabajo realizado en los bucles es O (N). Por lo tanto, la complejidad del tiempo es O (N) . Nunca tenemos más de N valores en la tabla hash en un momento dado, por lo que la complejidad del espacio también es O (N) .

Parece que debería poder crear un diccionario de . A medida que recorre la lista, puede poner números allí, como
12 – 1 (“Vi el número 12 en la posición 1”)
14 – 2
18 – 3
12 -4: Otro 12 estaba en la posición 4. Eso es una repetición de algo en el diccionario, por lo que la longitud es la posición actual (4) – la posición original (1) = 3. Mejor hasta ahora.
19 -5
8 – 6
1 – 7
15 – 8
14 – 9: Otro 14 estaba en la posición 9. Eso es una repetición de algo en el diccionario, por lo que la longitud es la posición actual (9) – la posición original (2) = 7. Mejor hasta ahora.
etc.

Deberías dar la vuelta hasta llegar a tu primer punto de colisión nuevamente. (Por lo tanto, puede dar la vuelta hasta que regrese a la posición 4, en caso de que el final de la lista tenga más valores no colisionantes). Si no hay colisión, la longitud es la longitud de la lista.