Técnicas comunes para cepillar preguntas en listas vinculadas: punteros rápidos y lentos

Poderosa, inamovible como una montaña, la verdadera fuerza que no perderá ante uno mismo. 

Revisión anterior:

Estructura de datos: lista enlazada individualmente

Pregunta sobre el cepillo de hebilla de mesa de un solo enlace

Directorio de artículos

Ejemplo clásico: el nodo intermedio de la lista enlazada

Análisis de temas e introducción de ideas de doble puntero. 

Diagrama de puntero dual

código central leetcode

Juzgando la lista circular enlazada: la extensión de los punteros rápido y lento es un problema de recuperación

análisis de tema, gráfico

código central leetcode


  Hola a todos, soy Ji Ning.

  La mayoría de las entrevistas y pruebas escritas en la parte de la lista vinculada de estructura de datos están en la parte de la lista vinculada única, y la mayoría de las preguntas son nodos principales sin bits centinela, y las preguntas suelen ser relativamente difíciles. Este artículo le presentará una técnica común para resolver problemas aquí en una lista unidireccional: punteros rápidos y lentos.

  Los llamados punteros rápido y lento significan que hay dos punteros para mantener la lista enlazada individualmente, generalmente definidos como lento y rápido, y estos dos punteros atraviesan la lista enlazada a diferentes velocidades.

Ejemplo clásico: el nodo intermedio de la lista enlazada

  Dado el nodo principal de la lista enlazada individualmente  head , busque y devuelva el nodo medio de la lista enlazada. Si hay dos nodos intermedios, devuelve el segundo nodo intermedio.

Análisis de temas e introducción de ideas de doble puntero. 

  En esta pregunta, si está buscando el elemento intermedio de la matriz, puede ser relativamente simple: calcular directamente el tamaño de la matriz y luego estipular que solo se puede atravesar la mitad del contenido. Pero en la lista enlazada, no sabes nada excepto el contenido del nodo actual y la dirección del siguiente nodo, por lo que no puedes controlar dónde va el puntero.

  Existe un método particularmente ingenioso, que consiste en definir dos punteros, un puntero retrocede un paso lento a la vez, lento = lento->siguiente; un puntero retrocede dos pasos a la vez, rápido = rápido -> siguiente -> siguiente, de esta manera, cuando el puntero rápido o rápido->siguiente se convierte en un puntero NULL, el puntero lento simplemente va al centro de la lista vinculada, encontrando así el nodo medio de la lista vinculada.

Diagrama de puntero dual

Cuando la longitud de la lista enlazada es impar

Cuando la longitud de la lista enlazada es par 

 

código central leetcode

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode*slow,*fast;
    slow=head;
    fast=head;
    while(fast!=NULL&&fast->next!=NULL)
    {
        fast=fast->next->next;
        slow=slow->next;
    }
    return slow;
}

  Una cosa a tener en cuenta en el código es que debido a que el puntero rápido avanza "dos pasos" a la vez, la condición de terminación del bucle es que rápido o rápido->siguiente está vacío y finalmente devuelve el puntero lento.

Juzgando la lista circular enlazada: la extensión de los punteros rápido y lento es un problema de recuperación

Pregunta: Dado el nodo principal de una lista vinculada  head , determine si hay un anillo en la lista vinculada.

  Si hay un nodo en la lista vinculada al que se puede  next acceder nuevamente siguiendo continuamente el puntero, entonces hay un ciclo en la lista vinculada. Para representar un anillo en una lista vinculada determinada, el sistema de evaluación utiliza internamente un número entero  pos para representar la posición en la lista vinculada donde está conectada la cola de la lista vinculada (el índice comienza desde 0). pos No pasado como parámetro  . Solo para identificar la situación real de la lista vinculada.

Devuelve si hay un ciclo en la lista vinculada  true . En caso contrario, regresa  false .

análisis de tema, gráfico

  Como se muestra en la figura: la lista vinculada de arriba ingresa al anillo en d3, el campo de puntero de d6 apunta a d3, y luego la lista vinculada circulará en el anillo de d3——d4——d5——d6——d3.

  En primer lugar, esta pregunta no proporciona la posición para ingresar al ring, por lo que hay muchas posibilidades para ingresar al ring, lo que excluye la idea de atravesar la lista vinculada. Esta pregunta también puede utilizar el método de punteros rápidos y lentos. El puntero rápido y el puntero lento comienzan a caminar hacia atrás desde el puntero principal al mismo tiempo. El puntero rápido da dos pasos a la vez y el puntero lento da un paso. a la vez para ver si los dos punteros pueden coincidir.

  Si el reloj vinculado tiene anillo, el puntero rápido y el puntero lento deben coincidir, de lo contrario no se encontrarán. Este principio de persecución es similar a ir al patio de recreo a correr vueltas con tu novia, empiezas al mismo tiempo, siempre que corras más rápido que ella y no pares hasta encontrarte, podrás lograr vueltas. 

  Por lo tanto, siempre que el puntero rápido y el puntero lento retrocedan y descubran que apuntan al mismo (rápido == lento), significa que la lista vinculada tiene un bucle (un bucle). Si rápido o rápido-> siguiente está vacío, significa que el recorrido de la lista vinculada ha finalizado y la lista vinculada no tiene anillos. 

código central leetcode

bool hasCycle(struct ListNode *head) {
    struct ListNode *slow=head;
    struct ListNode *fast=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(fast==slow)
            return true;
    }
    return false;
}

  Esta es la técnica común para resolver preguntas en la parte de la lista de enlace único que le presentó el blogger: el puntero rápido, gracias por mirar.

Supongo que te gusta

Origin blog.csdn.net/zyb___/article/details/132024454
Recomendado
Clasificación