Leetcode brushing notes (C++) - linked list

Leetcode brushing notes (C++) - linked list

Sort out the ideas in the process of brushing the questions, and summarize and share them here.
github address: https://github.com/lvjian0706/Leetcode-solutions
The github project is just newly created, and the organized code and ideas will be uploaded one after another. The code is based on C++ and python. At the same time, the basic sorting algorithm will also be sorted and uploaded.

21. Merge two sorted linked lists

Merges two ascending lists into a new ascending list and returns. The new linked list is formed by splicing all the nodes of the given two linked lists.

Example:
Input: 1->2->4, 1->3->4
Output: 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. Delete duplicate elements in sorted linked list II

Given a sorted linked list, delete all nodes containing duplicate numbers, and only keep the numbers that do not appear repeatedly in the original linked list.

Example 1:
Input: 1->2->3->3->4->4->5
Output: 1->2->5
Example 2:
Input: 1->1->1->2-> 3
output: 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. Delete duplicate elements in sorted list

Given a sorted linked list, remove all duplicate elements such that each element appears only once.

Example 1:
Input: 1->1->2
Output: 1->2
Example 2:
Input: 1->1->2->3->3
Output: 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. Separate linked list

Given a linked list and a certain value x, partition the linked list such that all nodes less than x precede nodes greater than or equal to x.

You should preserve the initial relative position of each node in the two partitions.

Example:
Input: head = 1->4->3->2->5->2, x = 3
Output: 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. Reverse Linked List II

Reverses the linked list from position m to n. Use one sweep to complete the inversion.

Explanation:
1 ≤ m ≤ n ≤ length of linked list.

Example:
Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 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. Copy Linked List with Random Pointers

Given a linked list, each node contains an additional random pointer, which can point to any node in the linked list or an empty node.

Requests to return a deep copy of this linked list.

We represent a linked list in input/output by a linked list of n nodes. Each node is represented by a [val, random_index]:

val: An integer representing Node.val.
random_index: The index of the node pointed to by the random pointer (ranging from 0 to n-1); null if it does not point to any node.

/*
// 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. Circular Linked List

Given a linked list, determine whether there is a cycle in the linked list.

To represent a cycle in a given list, we use the integer pos to denote the position in the list where the tail of the list joins (indexes start at 0). If pos is -1, there are no cycles in the list.

Example 1:
Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a ring in the linked list whose tail is connected to the second node.
Example 2:
Input: head = [1,2], pos = 0
Output: true
Explanation: There is a ring in the linked list whose tail is connected to the first node.
Example 3:
Input: head = [1], pos = -1
Output: false
Explanation: There is no cycle in the linked list.
Advanced:
Can you solve this problem with O(1) (ie, constant) memory?

/**
 * 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. Circular Linked List II

Given a linked list, return the first node where the linked list starts entering the ring. Returns null if the linked list is acyclic.

To represent a cycle in a given list, we use the integer pos to denote the position in the list where the tail of the list joins (indexes start at 0). If pos is -1, there are no cycles in the list.

Description: Modification of the given linked list is not allowed.

Example 1:
Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1
Explanation: There is a ring in the linked list whose tail connects to the second node.
Example 2:
Input: head = [1,2], pos = 0
Output: tail connects to node index 0
Explanation: There is a ring in the linked list whose tail is connected to the first node.
Example 3:
Input: head = [1], pos = -1
Output: no cycle
Explanation: There is no cycle in the linked list.

/**
 * 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. Rearrange Linked List

Given a singly linked list L: L0→L1→…→Ln-1→Ln,
after rearranging it becomes: L0→Ln→L1→Ln-1→L2→Ln-2→…

You can't just change the value inside the node, but need to actually swap the node.

Example 1:
Given linked list 1->2->3->4, rearrange to 1->4->2->3.
Example 2:
Given linked list 1->2->3->4->5 , rearranged as 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. Sorting Linked List

Sort a linked list in O(n log n) time complexity and constant level space complexity.

Example 1:
Input: 4->2->1->3
Output: 1->2->3->4
Example 2:
Input: -1->5->3->4->0
Output: -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. Reverse Linked List

Reverse a singly linked list.

Example:
Input: 1->2->3->4->5->NULL
Output: 5->4->3->2->1->NULL
Advanced:
You can reverse the linked list iteratively or recursively . Can you solve this problem two ways?

/**
 * 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. Palindrome Linked List

Please determine whether a linked list is a palindromic linked list.

Example 1:
Input: 1->2
Output: false
Example 2:
Input: 1->2->2->1
Output: true
Advanced:
Can you use O(n) time complexity and O(1) space Complexity to solve this problem?

/**
 * 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;
    }
};

Guess you like

Origin blog.csdn.net/weixin_43273742/article/details/107741221