141. Ciclo de lista enlazada
Dado el encabezado , el encabezado de una lista vinculada, determine si la lista vinculada tiene un ciclo.
Hay un ciclo en una lista enlazada si hay algún nodo en la lista al que se puede acceder nuevamente siguiendo continuamente el siguiente puntero. Internamente, pos se usa para indicar el índice del nodo al que está conectado el siguiente puntero de la cola. Tenga en cuenta que pos no se pasa como parámetro.
Devuelve verdadero si hay un ciclo en la lista vinculada. De lo contrario, devuelve falso.
Ejemplo 1:
Entrada: head = [3,2,0,-4], pos = 1
Salida: true
Explicación: Hay un ciclo en la lista vinculada, donde la cola se conecta al primer nodo (indexado en 0).
Ejemplo 2:
Entrada: head = [1,2], pos = 0
Salida: true
Explicación: Hay un ciclo en la lista vinculada, donde la cola se conecta al nodo 0.
Ejemplo 3:
Entrada: head = [1], pos = -1
Salida: false
Explicación: No hay ningún ciclo en la lista vinculada.
Restricciones:
- El número de nodos en la lista está en el rango [ 0 , 1 0 4 ] [0, 10^4][ 0 ,1 04 ].
- − 1 0 5 < = Nodo . valor <= 1 0 5 -10^5 <= Valor.nodo <= 10^5− 1 05<=Nodo . _ _ _ va l _<=1 05
- pos es -1 o un índice válido en la lista vinculada.
De: LeetCode
Enlace: 141. Ciclo de lista enlazada
Solución:
Ideas:
Idea fundamental:
Imaginemos dos corredores en una pista circular, uno de los corredores (la liebre) es mucho más rápido que el otro (la tortuga). Si comienzan en la misma posición y corren en la misma dirección, el corredor más rápido (liebre) eventualmente dará vuelta al corredor más lento (tortuga). De manera similar, en una lista vinculada, si hay un ciclo, un puntero más rápido eventualmente se encontrará con el puntero más lento dentro del ciclo.
Explicación del código:
1. Inicialización:
- Tenemos dos punteros: tortuga (que se mueve lentamente) y liebre (que se mueve rápido). Ambos comienzan al principio de la lista vinculada.
2. Movimiento:
- La tortuga se mueve paso a paso (tortuga = tortuga->siguiente).
- La liebre avanza dos pasos a la vez (liebre = liebre->siguiente->siguiente).
3. Comprobación del ciclo:
- Si no hay ningún ciclo en la lista vinculada, la liebre (que se mueve más rápido) eventualmente llegará al final de la lista y encontrará un puntero NULL.
- Si hay un ciclo, la liebre eventualmente “lamerá” a la tortuga y se encontrarán en algún punto dentro del ciclo.
4. Terminación del bucle:
- El ciclo continúa mientras liebre y liebre->siguiente no sean NULL.
- Si los punteros de tortuga y liebre se encuentran (tortuga == liebre), indica la presencia de un ciclo y la función devuelve verdadero.
- Si el ciclo termina sin que los punteros se encuentren, no hay ciclo y la función devuelve falso.
Código:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
if (!head) return false; // If list is empty
struct ListNode *tortoise = head; // Slow pointer
struct ListNode *hare = head; // Fast pointer
while (hare != NULL && hare->next != NULL) {
tortoise = tortoise->next; // Move slow pointer one step
hare = hare->next->next; // Move fast pointer two steps
if (tortoise == hare) return true; // If they meet, there's a cycle
}
return false; // If loop exits, there's no cycle
}