Lista vinculada al entrenamiento del algoritmo elemental de LeetCode (completada)

Introducción

Anterior: Cadena de entrenamiento del algoritmo elemental LeetCode

Siguiente: Árbol de entrenamiento del algoritmo primario de LeetCode

Originalmente quería comenzar con el nivel principiante e intermedio y los algoritmos de entrevistas corporativas, pero al final optamos por comenzar desde lo básico, porque no cepillamos preguntas con el propósito de cepillar preguntas, sino ejercitar una especie de algoritmo pensando en el proceso de cepillado de preguntas, después de mucho entrenamiento. Forme una visión única del algoritmo, cultive la sensibilidad al algoritmo, vea el problema, un plan para resolver el problema puede aparecer en el cerebro y, lentamente, genere confianza desde el principio, y esto también es para el complejo algoritmo detrás Sentar las bases para ideas de resolución de problemas.

Introducción al algoritmo primario de LeetCode

Si también quieres entrenar tu propio pensamiento algorítmico, también puedes unirte a mí, comenzando desde el algoritmo elemental, inicia tu viaje del algoritmo: algoritmo elemental .

Un poco de su propio pensamiento: no mire la respuesta después de leer la pregunta y luego recite la pregunta, de modo que la memoria del algoritmo implementado no sea fuerte, debe tener su propio pensamiento; y no escriba sobre IDEA al principio, Asegúrese de intentar escribirlo en la pizarra proporcionada por leetCode y finalmente colóquelo en IDEA para ver si hay algún problema, a fin de consolidar su uso y competencia básica de API; otro punto es ser audaz, no el costo de prueba y error en la entrevista Baja, intenta incorporar nuestras ideas al código.

Debido a problemas de espacio, el blog solo enumera ejemplos y sus propias respuestas de resolución de problemas. Para obtener más detalles, puede hacer clic directamente en el tema para ver.

Eliminar el nodo en la lista vinculada

Escriba una función para eliminar un nodo dado (no final) en una lista vinculada, y solo se le dará el nodo requerido para ser eliminado.

Hay una lista vinculada - head = [4,5,1,9], que se puede expresar como:
Inserte la descripción de la imagen aquí
Ejemplo 1:
Entrada: head = [4,5,1,9], nodo = 5
Salida: [4,1,9 ]
Explicación: Dado el segundo nodo en su lista vinculada con valor 5, después de llamar a su función, la lista vinculada debería convertirse en 4 -> 1 -> 9.

Ejemplo 2:
Entrada: cabeza = [4,5,1,9], nodo = 1
Salida: [4,5,9]
Explicación: Dado el tercer nodo con valor 1 en su lista enlazada, entonces está llamando Después de la función, la lista vinculada debería convertirse en 4 -> 5 -> 9.

Descripción:

  • La lista vinculada contiene al menos dos nodos.
  • Los valores de todos los nodos de la lista vinculada son únicos.
  • El nodo dado no es el nodo final y debe ser un nodo válido en la lista vinculada.
  • No devuelva ningún resultado de su función.
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public void deleteNode(ListNode node) {
        node.val = node.next.val;
        node.next = node.next.next;
    }
}

Tiempo de ejecución: 0 ms
Consumo de memoria: 39,5 MB La
lista enlazada individualmente no puede encontrar el nodo anterior del nodo actual, por lo que en este momento consideramos trasponer el valor del nodo actual al valor del siguiente nodo, y su siguiente nodo se cambia al siguiente. Nodos de nodos. (Las muñecas están prohibidas).

Eliminar el nodo N de la parte inferior de la lista vinculada

Dada una lista vinculada, elimine el n-ésimo nodo de la parte inferior de la lista vinculada y devuelva el nodo principal de la lista vinculada.
Ejemplo:
Dada una lista vinculada: 1-> 2-> 3-> 4-> 5, y n = 2.
Cuando se elimina el penúltimo nodo, la lista vinculada se convierte en 1-> 2-> 3-> 5.

Explicación: La
garantía n proporcionada es válida.

Avanzado:
¿Puedes intentar usar un escaneo para lograrlo?

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
         ListNode fakeNode = new ListNode(0);
        fakeNode.next = head;
        
        ListNode target = head;
        int count = 1;
        while(target.next != null) {
            target = target.next;
            count ++;
        }

        int k = 0;
        target = fakeNode;
        while(k != count - n) {
            target = target.next;
            k++;
        }
        
        target.next = target.next.next;
        
        return fakeNode.next;
    }
}

Tiempo de ejecución: 1 ms
Consumo de memoria: 37,8 MB

El propósito de agregar un primer nodo falso es evitar la situación extrema de un nodo o el último nodo y el primer nodo, y finalmente tenemos que volver al nodo principal. Se pueden realizar dos ciclos.
Pero hay otra forma es la forma de doble puntero.

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
           ListNode fakeNode = new ListNode(0);
        fakeNode.next = head;

        ListNode target = fakeNode;
        for(int i = 0; i < n; i++) {
            target = target.next;
        }
        ListNode result = fakeNode;
        while(target.next != null) {
            result = result.next;
            target = target.next;
        }

        result.next = result.next.next;
        return fakeNode.next;
    }
}

208/208 casos de prueba aprobados
Estado: Aprobado Tiempo de
ejecución: 1 ms
Consumo de memoria: 38,3 MB

Cabe señalar que la adición del primer punto auxiliar es muy importante.

Lista vinculada inversa

Invierta una lista enlazada individualmente.
Ejemplo:
Entrada: 1-> 2-> 3-> 4-> 5-> NULL
Salida: 5-> 4-> 3-> 2-> 1-> NULL

Avanzado:
puede invertir la lista vinculada de forma iterativa o recursiva. ¿Puedes resolver este problema de dos formas?

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
   
    public ListNode reverseList(ListNode head) {
        if(head == null) return null;
         ListNode nextv = head.next;
        ListNode curv = head;
        ListNode prev = null;
        while(curv != null) {
            curv.next = prev;
            prev = curv;
            curv = nextv;
            if (nextv != null) {
                nextv = nextv.next;
            }
        }

        return prev;
    }
}

27/27 casos de prueba aprobados
Estado: Aprobado Tiempo de
ejecución: 0 ms
Consumo de memoria: 39,7 MB

Los tres parámetros se intercambian, principalmente para determinar cuándo detenerse. Lo que deberíamos juzgar es curv porque en realidad asigna el valor nextv cada vez. Cuando es nulo, significa que nextv.next ya es nulo en la última encuesta, y nextv debe ser nulo.

Método de doble puntero:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
   
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null) return head;
        ListNode temp = null;
        ListNode cur = head;
        ListNode pre = null;
        while(cur != null){
            temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }

        return pre;
    }
}

Recurrencia:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
   
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null) return head;
        
        ListNode cur = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return cur;
    }
}
Fusionar dos listas enlazadas ordenadas

Combine dos listas vinculadas ascendentes en una nueva lista vinculada ascendente y regrese. La nueva lista enlazada se compone de empalmar todos los nodos de las dos listas enlazadas dadas.

Ejemplo:
Entrada: 1-> 2-> 4, 1-> 3-> 4
Salida: 1-> 1-> 2-> 3-> 4-> 4

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
       ListNode listNode = new ListNode(-1);

        ListNode preNode = listNode;

        while (l1 != null && l2 != null) {
            if (l1.val >= l2.val) {
                preNode.next = l2;
                l2 = l2.next;
            } else {
                preNode.next = l1;
                l1 = l1.next;
            }
            preNode = preNode.next;
        }

        preNode.next = (l1 == null ? l2 : l1);

        return listNode.next;
    }
}

208/208 casos de prueba aprobados
Estado: Aprobado Tiempo de
ejecución: 1 ms
Consumo de memoria: 39.5 MB
Esta pregunta es lo mismo que fusionar dos grupos de árboles de ordenación, lo que equivale a proporcionarnos dos punteros, solo necesitamos comparar el tamaño y colocar el nodo Vaya a una nueva lista vinculada y devuelva el siguiente nodo principal.

Lista enlazada de palíndromos
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
       if (head == null || head.next == null) return true;

        ListNode target1 = head;
        ListNode target2 = head;
        //计算数目
        int count = 0;
        while (target1 != null) {
            target1 = target1.next;
            count++;
        }
        //找出前半部分最后一个
        int k = 1;
        target1 = head;
        while (k < count / 2) {
            target1 = target1.next;
            k++;
        }
        //找到后半部分第一个
        target2 = (count % 2 == 0 ? target1.next : target1.next.next);
		//断开链表
        target1.next = null;
		//反转前半部分链表
       ListNode listNode =  reverseList(head);
    
		//逐个判断是否相等
        while (listNode != null) {
            if (target2.val != listNode.val) {
                return false;
            }
            listNode = listNode.next;
            target2 = target2.next;
        }
        return true; 
    }
  
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null) return head;
        
        ListNode cur = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return cur;
    } 
}

26/26 casos de prueba aprobados
Estado: Aprobado Tiempo de
ejecución: 2 ms
Consumo de memoria: 43,8 MB

// TODO necesita agregar un puntero rápido y lento

Lista enlazada circular

Dada una lista vinculada, determine si hay un anillo en la lista vinculada.

Para representar los anillos en una lista vinculada dada, usamos el entero pos para indicar la posición donde el final de la lista vinculada está conectado a la lista vinculada (el índice comienza desde 0). Si pos es -1, entonces no hay ningún anillo en la lista vinculada.

Ejemplo 1:
Entrada: head = [3,2,0, -4], pos = 1
Salida: true
Explicación: Hay un anillo en la lista enlazada y su cola está conectada al segundo nodo.
Inserte la descripción de la imagen aquí

Ejemplo 2:
Entrada: cabeza = [1,2], pos = 0
Salida: verdadera
Explicación: Hay un anillo en la lista enlazada y su cola está conectada al primer nodo.
Inserte la descripción de la imagen aquí

Ejemplo 3:
Entrada: cabeza = [1], pos = -1
Salida: falso
Explicación: No hay ningún anillo en la lista vinculada.
Inserte la descripción de la imagen aquí

Avanzado:
¿Puede resolver este problema con la memoria O (1) (es decir, constante)?

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null || head.next == null) return false;
        
        
        ListNode p0 = head;
        ListNode p1 = head.next;
        
        while(p0 != null && p1 != null && p1.next != null) {
        	//这里换成==会更快 equals会慢
            if(p0==p1){
                return true;
            }
            p0 = p0.next;
            p1 = p1.next.next;
        }
        
        return false;
    }
}

17/17 casos de prueba aprobados
Estado: Aprobado Tiempo de
ejecución: 0 ms
Consumo de memoria: 40,2 MB

Los punteros rápido y lento se encontrarán después de un cierto círculo. Similar a una persona rápida y una persona lenta en la pista, la persona rápida adelantará a la persona lenta y se encontrará.

Supongo que te gusta

Origin blog.csdn.net/u011148116/article/details/107181994
Recomendado
Clasificación