Notas de cepillado de Leetcode (C++) - lista enlazada

Notas de cepillado de Leetcode (C++) - lista enlazada

Ordene las ideas en el proceso de repasar las preguntas, resúmalas y compártalas aquí.
dirección de github: https://github.com/lvjian0706/Leetcode-solutions
El proyecto de github se creó recientemente, y el código y las ideas se cargarán uno tras otro. El código está basado en C++ y python. Al mismo tiempo, el algoritmo de clasificación básico también se clasificará y cargará.

21. Combinar dos listas enlazadas ordenadas

Fusiona dos listas ascendentes en una nueva lista ascendente y regresa. La nueva lista enlazada se forma empalmando 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.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    
    
public:
    /*
    合并有序链表:类似归并排序的思路
    */
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
    
    
        ListNode node(0);
        ListNode* new_head = &node;
        while(l1 && l2){
    
    
            if(l1->val <= l2->val){
    
    
                new_head->next = l1;
                l1 = l1->next;
            }
            else{
    
    
                new_head->next = l2;
                l2 = l2->next;
            }
            new_head = new_head->next;
        }
        while(l1){
    
    
            new_head->next = l1;
            l1 = l1->next;
            new_head = new_head->next;
        }
        while(l2){
    
    
            new_head->next = l2;
            l2 = l2->next;
            new_head = new_head->next;
        }
        return node.next;
    }
};

82. Eliminar elementos duplicados en la lista enlazada ordenada II

Dada una lista enlazada ordenada, elimine todos los nodos que contengan números duplicados y solo conserve los números que no aparecen repetidamente en la lista enlazada original.

Ejemplo 1:
Entrada: 1->2->3->3->4->4->5
Salida: 1->2->5
Ejemplo 2:
Entrada: 1->1->1->2-> 3
salidas: 2->3

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    删除重复节点,只保留没有重复出现的数字:
    1. 为了避免头节点重复需要删除,新建一个头节点指向原来的头节点,最后返回新建节点的next;
    2. 定义last和fast节点用来遍历链表,并找出重复节点:
    2.1 last和fast初始化为head节点,循环判断last和fast的next是否相等,如果相等,fast前进一位;
    2.2 如果fast发生了变化,也就是last和fast不是同一个节点时,说明从last到fast之间是重复元素,new_head的next指向fast的下一个元素;
    2.3 如果last和fast是同一个节点时,说明该元素不是重复元素,new_head前进到该元素;
    2.4 last和fast前进一位,保证永远在new_head前面一位;
    */
    ListNode* deleteDuplicates(ListNode* head) {
    
    
        ListNode node(0);
        ListNode* new_head = &node;
        new_head->next = head;
        ListNode* last = head;
        ListNode* fast = head;
        while(fast && fast->next){
    
    
            while(fast->next && last->val == fast->next->val){
    
    
                fast = fast->next;
            }
            if(last==fast){
    
    
                new_head = last;
            }
            else{
    
    
                new_head->next = fast->next;
            }
            last = new_head->next;
            fast = new_head->next;
        }
        return node.next;
    }
};

83. Eliminar elementos duplicados en la lista ordenada

Dada una lista ordenada ordenada, elimine todos los elementos duplicados de modo que cada elemento aparezca solo una vez.

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

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    使用一个指针进行遍历:
    1. 如果没有元素或者只有1个元素,直接返回;
    2. 遍历链表,当下一个元素与当前元素相等时,指针的next指向next的next,用以删除重复的元素,直到下一个元素与当前元素不相等为止;
    3. 指针指向下一个元素(与当前元素不相等的第一个元素);
    */
    ListNode* deleteDuplicates(ListNode* head) {
    
    
        if(!head || !head->next) return head;
        ListNode* newHead = head;
        while(newHead && newHead->next){
    
    
            if(newHead->next->val==newHead->val){
    
    
                newHead->next = newHead->next->next;
            }
            else{
    
    
                newHead = newHead->next;
            }
        }
        return head;
    }
};

86. Lista enlazada separada

Dada una lista enlazada y un cierto valor x, divida la lista enlazada de manera que todos los nodos menores que x precedan a los nodos mayores o iguales a x.

Debe conservar la posición relativa inicial de cada nodo en las dos particiones.

Ejemplo:
Entrada: cabezal = 1->4->3->2->5->2, x = 3
Salida: 1->2->2->4->3->5

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    分隔链表:
    定义两个节点small_head和large_head,前者作为头节点存储小于x的节点,后者作为头节点存储大于等于x的节点,最后进行拼接;
    注意结果链表的尾部应该为null;
    */
    ListNode* partition(ListNode* head, int x) {
    
    
        ListNode node1(0);
        ListNode* small_head = &node1;
        ListNode node2(0);
        ListNode* large_head = &node2;
        while(head){
    
    
            if(head->val<x){
    
    
                small_head->next = head;
                small_head = small_head->next;
            }
            else{
    
    
                large_head->next = head;
                large_head = large_head->next;
            }
            head = head->next;
        }
        small_head->next = node2.next;
        large_head->next = NULL;
        return node1.next;
    }
};

92. Lista de enlaces inversos II

Invierte la lista enlazada de la posición m a la n. Use un barrido para completar la inversión.

Explicación:
1 ≤ m ≤ n ≤ longitud de la lista enlazada.

Ejemplo:
Entrada: 1->2->3->4->5->NULL, m = 2, n = 4
Salida: 1->4->3->2->5->NULL

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    反转从m到n的链表:迭代法
    使用first指针指向位置m,first_pre指向m-1,temp设为null,last指向位置m+1,last_next指向位置n+1;
    使用fist,last以及temp将位置m到n进行反转,接着将first_pre指向反转后的子链表头,反转后的子链表尾指向n+1;
    */
    ListNode* reverseBetween(ListNode* head, int m, int n) {
    
    
         ListNode* first = head;
         ListNode node(0);
         ListNode* first_pre = &node;
         first_pre->next = head;
         /*
        将first指针指向位置m,first_pre指向位置m-1;
         */
        for(int i=0; i<m-1; i++){
    
    
            first = first->next;
            first_pre = first_pre->next;
        }
        ListNode* last = first->next;
        ListNode* temp = NULL;
        /*
        使用fist,last以及temp将位置m到n进行反转,此时temp指向位置m,first指向位置m+1;
        */
        for(int i=m; i<n+1; i++){
    
    
            first->next = temp;
            temp = first;
            first = last;
            if(last) last = last->next;
        }
        first_pre->next->next = first;
        first_pre->next = temp;
        return node.next;
    }
};

138. Copiar lista enlazada con punteros aleatorios

Dada una lista enlazada, cada nodo contiene un puntero aleatorio adicional, que puede apuntar a cualquier nodo de la lista enlazada o a un nodo vacío.

Solicitudes para devolver una copia profunda de esta lista vinculada.

Representamos una lista enlazada en entrada/salida por una lista enlazada de n nodos. Cada nodo está representado por un [val, random_index]:

val: un número entero que representa Node.val.
random_index: el índice del nodo al que apunta el puntero aleatorio (que va de 0 a n-1); nulo si no apunta a ningún nodo.

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
    
    
public:
    /*
    复制带随机指针的链表:深拷贝
    1. 循环遍历链表,一边遍历一边新建节点,将新节点赋值为与该节点一样的值,然后插入到该节点后边;
    2. 再次循环遍历新链表,步长为2,一边遍历一边将后边的节点(1中新建的节点)的random赋值为与前边节点(原始节点)一致;
    3. 将新链表拆分
    */
    Node* copyRandomList(Node* head) {
    
    
        Node* insert_head = head;
        while(insert_head){
    
    
            Node* temp_node = new Node(insert_head->val);
            temp_node->next = insert_head->next;
            insert_head->next = temp_node;
            insert_head = insert_head->next->next;
        }
        Node* random_head = head;
        while(random_head && random_head->next){
    
    
            if(random_head->random) random_head->next->random = random_head->random->next;
            else random_head->next->random = NULL;
            random_head = random_head->next->next;
        }
        Node node(0);
        Node* copy_head = &node;
        Node* new_head = head;
        while(new_head && new_head->next){
    
    
            copy_head->next = new_head->next;
            new_head->next = new_head->next->next;
            new_head = new_head->next;
            copy_head = copy_head->next;
        }
        copy_head->next = NULL;
        return node.next;
    }
};

141. Lista enlazada circular

Dada una lista enlazada, determine si hay un ciclo en la lista enlazada.

Para representar un ciclo en una lista dada, usamos el número entero pos para indicar la posición en la lista donde se une la cola de la lista (los índices comienzan en 0). Si pos es -1, no hay ciclos en la lista.

Ejemplo 1:
Entrada: cabeza = [3,2,0,-4], pos = 1
Salida: verdadero
Explicación: Hay un anillo en la lista enlazada cuya cola está conectada al segundo nodo.
Ejemplo 2:
Entrada: cabeza = [1,2], pos = 0
Salida: verdadero
Explicación: Hay un anillo en la lista enlazada cuya cola está conectada al primer nodo.
Ejemplo 3:
Entrada: cabeza = [1], pos = -1
Salida: falso
Explicación: No hay ningún ciclo en la lista enlazada.
Avanzado:
¿Puedes resolver este problema con memoria O(1) (es decir, constante)?

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    判断链表是否有环,使用快慢指针
    快指针每次走两步,慢指针每次走一步,看是否可以碰面;主要关注边界情况
    */
    bool hasCycle(ListNode *head) {
    
    
        if(!head || !head->next) return false;
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast && fast->next){
    
    
            fast = fast->next->next;
            slow = slow->next;
            if(fast==slow) return true;
        }
        return false;
    }
};

142. Lista circular enlazada II

Dada una lista enlazada, devuelve el primer nodo donde la lista enlazada comienza a entrar en el anillo. Devuelve nulo si la lista enlazada es acíclica.

Para representar un ciclo en una lista dada, usamos el número entero pos para indicar la posición en la lista donde se une la cola de la lista (los índices comienzan en 0). Si pos es -1, no hay ciclos en la lista.

Descripción: No se permite la modificación de la lista enlazada dada.

Ejemplo 1:
Entrada: cabeza = [3,2,0,-4], pos = 1
Salida: la cola se conecta al índice de nodo 1
Explicación: Hay un anillo en la lista enlazada cuya cola se conecta al segundo nodo.
Ejemplo 2:
Entrada: cabeza = [1,2], pos = 0
Salida: la cola se conecta al índice de nodo 0
Explicación: Hay un anillo en la lista enlazada cuya cola está conectada al primer nodo.
Ejemplo 3:
Entrada: cabeza = [1], pos = -1
Salida: sin ciclo
Explicación: No hay ciclo en la lista enlazada.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    循环链表:
    1. 首先判断是否是环,使用快慢指针,快指针每次走2步,慢指针每次走1步,看是否相遇,不相遇则返回null;
    2. 如果相遇,设慢指针走了s,则快指针已经走了2s,假设从head到环的入口为a,环的长度为b,则s=nb,快指针比慢指针多走了nb;
    3. 想要计算环的入口a,可以使用两个指针,一个在head处走a步,一个在相遇处走a步,此时,一个指针的位置为a,一个为a+nb,因为有环,所以a=a+nb;
    4. 最终的相遇位置为环的入口;
    */
    ListNode *detectCycle(ListNode *head) {
    
    
        if(!head || !head->next) return NULL;
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast && fast->next){
    
    
            fast = fast->next->next;
            slow = slow->next;
            if(fast==slow){
    
    
                slow = head;
                while(fast != slow){
    
    
                    fast = fast->next;
                    slow = slow->next;
                }
                return slow;
            }
        }
        return NULL;
    }
};

143. Reorganizar lista enlazada

Dada una lista enlazada simple L: L0→L1→…→Ln-1→Ln,
después de reorganizarla se convierte en: L0→Ln→L1→Ln-1→L2→Ln-2→…

No puede simplemente cambiar el valor dentro del nodo, sino que necesita intercambiar el nodo.

Ejemplo 1:
Dada la lista enlazada 1->2->3->4, reorganizar a 1->4->2->3
Ejemplo 2:
Dada la lista enlazada 1->2->3->4->5 , reordenado como 1->5->2->4->3.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    
    
public:
    /*
    递归反转链表
    */
    ListNode* reverseList(ListNode* head){
    
    
        if(!head || !head->next) return head;
        ListNode* new_head = reverseList(head->next);
        head->next->next = head;
        head->next = nullptr;
        return new_head;
    }
    /*
    重排列链表:将后半部分的链表倒序插入到前半部分链表中;
    1. 使用快慢指针找到后半部分链表;
    2. 反转后半部分链表;
    3. 将右半部分链表插入到左半部分链表中;
    */
    void reorderList(ListNode* head) {
    
    
        if(!head || !head->next) return;
        ListNode* fast = head->next;
        ListNode* slow = head;
        while(fast && fast->next){
    
    
            fast = fast->next->next;
            slow = slow->next;
        }
        ListNode* right_half = reverseList(slow->next);
        slow->next = nullptr;
        ListNode* new_head = head;
        while(new_head && right_half){
    
    
            ListNode* temp = right_half->next;
            right_half->next = new_head->next;
            new_head->next = right_half;
            right_half = temp;
            new_head = new_head->next->next;
        }
        /*
        当右半部分链表还有一个元素没有插入进去时,单独处理;
        */
        if(right_half){
    
    
            right_half->next = new_head->next;
            new_head->next = right_half;
        }
    }
};

148. Clasificación de la lista enlazada

Ordene una lista enlazada en complejidad de tiempo O (n log n) y complejidad de espacio de nivel constante.

Ejemplo 1:
Entrada: 4->2->1->3
Salida: 1->2->3->4
Ejemplo 2:
Entrada: -1->5->3->4->0
Salida: -1 ->0->3->4->5

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    新建头节点,进行归并排序;
    */
    ListNode* mergeSort(ListNode* left, ListNode* right){
    
    
        ListNode node(0);
        ListNode* new_head = &node;
        while(left && right){
    
    
            if(left->val<right->val){
    
    
                new_head->next = left;
                left =  left->next;
            }
            else{
    
    
                new_head->next = right;
                right = right->next;
            }
            new_head = new_head->next;
        }
        while(left){
    
    
            new_head->next = left;
            left =  left->next;
            new_head = new_head->next;
        }
        while(right){
    
    
            new_head->next = right;
            right =  right->next;
            new_head = new_head->next;
        }
        return node.next;
    }

    /*
    链表排序:
    O(nlogn) 时间复杂度以及常数级空间复杂度,考虑归并排序
    使用快慢指针找链表的中点,将链表分为前半部分和后半部分,递归的对前半部分以及后半部分进行排序,最后对两部分进行总的排序
    其中,在分割时,需要将前半部分的尾指针next赋为null,将链表切断,否则会无限递归;后半部分的起始点则为slow->next;
    */
    ListNode* sortList(ListNode* head) {
    
    
        if(!head || !head->next) return head;
        ListNode* fast = head->next;
        ListNode* slow = head;
        while(fast && fast->next){
    
    
            fast = fast->next->next;
            slow = slow->next;
        }
        ListNode* half = slow->next;
        slow->next = NULL;
        return mergeSort(sortList(head), sortList(half));
    }
};

206. Lista de enlaces inversos

Invertir 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 maneras?

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    原地反转链表:方法1.递归
    1. 递归结束条件:如果head为空或者链表只有1个节点,不需要反转,直接返回;
    2. 当head->next之后的节点已经反转好了,将新的头结点保存为new_head;
    3. 此时,头节点指向新链表的尾节点,需要将新链表的尾节点指向头节点(反转head和head->next),head->next->next = head;
    4. 将头节点的next赋为空;
    5. 返回新链表的头节点;
    */
    ListNode* reverseList(ListNode* head) {
    
    
        if(!head || !head->next) return head;
        ListNode* new_head = reverseList(head->next);
        head->next->next = head;
        head->next = NULL;
        return new_head;
    }
};



/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    原地反转链表:方法2.迭代
    1. 递归结束条件:如果head为空或者链表只有1个节点,不需要反转,直接返回;
    2. 使用三个指针,每次将当前指针指向前一个位置的指针,然后将三个指针同时向后移动一位;
    */
    ListNode* reverseList(ListNode* head) {
    
    
        ListNode* new_head = NULL;
        while(head){
    
    
            ListNode* head_next = head->next;
            head->next = new_head;
            new_head = head;
            head = head_next;
        }
        return new_head;
    }
};

234. Lista vinculada de palíndromo

Determine si una lista vinculada es una lista vinculada palindrómica.

Ejemplo 1:
Entrada: 1->2
Salida: falso
Ejemplo 2:
Entrada: 1->2->2->1
Salida: verdadero
Avanzado:
¿Puedes usar O(n) complejidad de tiempo y O(1) complejidad de espacio para resolver ¿este problema?

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    递归反转链表
    */
    ListNode* reverseList(ListNode* head){
    
    
        if(!head || !head->next) return head;
        ListNode* new_head = reverseList(head->next);
        head->next->next = head;
        head->next = NULL;
        return new_head;
    }
    /*
    判断是否是回文链表:
    1. 使用快慢指针找到链表中点,将链表断开;
    2. 将后半部分链表反转;
    3. 比较两个链表的相同位置的值是否一致;
    */
    bool isPalindrome(ListNode* head) {
    
    
        if(!head || !head->next) return true;
        ListNode* fast = head->next;
        ListNode* slow = head;
        while(fast && fast->next){
    
    
            fast = fast->next->next;
            slow = slow->next;
        }
        ListNode* right = reverseList(slow->next);
        slow->next = NULL;
        while(head && right){
    
    
            if(head->val != right->val) return false;
            head = head->next;
            right = right->next;
        }
        return true;
    }
};

Supongo que te gusta

Origin blog.csdn.net/weixin_43273742/article/details/107741221
Recomendado
Clasificación