[learning notes] [Leetcode explanation by category] - linked list

Posted by daxxy on Tue, 04 Jan 2022 05:04:06 +0100

Linked list related summary

The chain list problem is very easy to make mistakes. Please be sure to draw the process on the paper first. Please tear it by hand and draw a schematic diagram
Virtual head node + iteration + recursion

  1. The main types of linked lists are: single linked list, double linked list and circular linked list
  2. Storage mode of linked list: the nodes of the linked list are stored in memory in a decentralized manner and connected together through pointers.
  3. How to add, delete, modify and query the linked list.
  4. Performance analysis of array and linked list in different scenarios.

0. A topic examines the five common operations of the linked list! ‚Äč

Add, delete, modify and query

1. Linked list problem - threading, head inserting method

If you don't understand it, it will be annoying (recursion), and if you understand it, it will be great (head insertion)

[206. Reverse linked list]

——Method 1: three pointer iteration: flip the current node and save the next node and the previous node

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *pre = nullptr;//dummyHead
        ListNode *cur = head;
        while(cur!=nullptr){
            ListNode *tmp = cur->next;//Save cur - > next
            cur->next = pre;//reverse
            pre = cur;//Go back
            cur = tmp;//cur, go back
        }
        return pre;//At the end of the cycle, cur comes to the end, so return pre
    }
};

——Method 2: recursion


Detailed PPT diagram

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
    //The recursive termination condition is that the current node is empty or the next node is empty
        if(head == nullptr||head->next == nullptr){
            return head;
        }
        //cur here is the last node
        ListNode *cur = reverseList(head->next);//Recurse until the termination condition is triggered
        head->next->next = head;//If the linked list is 1 - > 2 - > 3 - > 4 - > 5, then the cur is 5 / / and the head is 4, the next head is 5, and the next head is empty
        head->next = nullptr;//To prevent the linked list from circulating, you need to set the head Next is set to null
        return cur;//Each recursive function returns cur, which is the last node
    }
};

[92. Reverse linked list II] - wonderful, extremely wonderful!

——Method 1: Threading

class Solution {
public:
    ListNode *reverseList(ListNode *head){
        ListNode *pre = nullptr;
        ListNode *cur = head;
        while(cur!=nullptr){
            ListNode *Next = cur->next;
            cur->next = pre;
            pre = cur;
            cur = Next;
        }
        return pre;
    }
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode *dummyHead = new ListNode(-1);//This can't be nullptr
        dummyHead->next = head;
        ListNode *pre = dummyHead;
        for(int i = 0;i<left-1;i++){pre = pre->next;}//Find pre for left
        ListNode *LeftNode = pre -> next;
        ListNode *RightNode = pre;//Use the following loop to find the RightNode
        for(int i = 0;i<right-left+1;i++){RightNode = RightNode->next;}
        ListNode *curr = RightNode->next;//Record rightnode - > next first! Or I won't find it
        RightNode -> next = nullptr;//Truncate head and tail
        pre->next = nullptr;
        reverseList(LeftNode);//reverse requirements
        pre->next = RightNode;//Resume the head and tail
        LeftNode->next = curr;
        return dummyHead->next;
    }
};

——Method 2: head insertion! Wonderful, wonderful!

Look at the picture

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode *dummyHead = new ListNode(-1);//It can't be nullptr here. It can be 0 or - 1 in parentheses
        dummyHead->next = head;
        ListNode *pre = dummyHead;
        for(int i = 0;i<left-1;i++){pre = pre->next;}
        ListNode *leftNode = pre->next;
        for(int i = 0;i<right-left;i++){//Take the value = 2 at left as an example
            ListNode *remove = leftNode->next;//Record the original next position 3
            leftNode->next = leftNode->next->next;//2 points to next 2 - > 4 of 3
            remove->next = pre->next;//3->2
            pre->next = remove;//1->3
            //After the first round, it becomes 1 - > 3 - > 2 - > 2 - > 4
        }
        return dummyHead->next;
    }
};

[203. Remove linked list elements]

——There are two ways to delete problems: iteration and recursion

dummy is used to solve the problem, so there is no need to consider one more head node problem;
In an iterative manner.

public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode *dummy = new ListNode(-1);
        dummy ->next = head;
        ListNode *tail = dummy;
        while(tail ->next){//Even if the list of questions brush less, not skilled
            if(tail ->next ->val ==val){tail->next = tail->next->next;}
            else{tail = tail->next;}
        }
        return dummy->next;
    }
};

[82. Delete duplicate Element II in the sorting linked list]

There is a linked list arranged in ascending order. Give you the head node of the linked list. Please delete all nodes with duplicate numbers in the linked list and only keep the numbers that do not appear repeatedly in the original linked list.

Returns a linked list of results in the same ascending order.
Input: head = [1,2,3,3,4,4,5]
Output: [1,2,5]

Basic ideas
Almost all linked list problems have similar problem-solving ideas.
1. Create a dummy header node to reduce boundary judgment, and the subsequent answer list will be followed by dummy
2. Use tail to represent the end of the currently valid linked list
3. Scan the linked list through the original head pointer

We will ensure that "when entering the outer loop, the head will not be the same as the previous node", so the insertion time:
1. There is no next node in the head. The head can be inserted
2.head has the following node, but the value is different from that of head. Head can be inserted

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        auto dummy = new ListNode(-1),tail = dummy;
        while(head){
            if(head->next == nullptr or head->val != head->next->val){
                tail->next = head;
                tail = head;
            }
            while(head->next and head->val == head->next->val) head = head->next;
            head = head->next;
        }
        tail->next = nullptr;//You can't forget if you point to the empty space behind the tail
        return dummy->next;
    }
};

[83. Delete duplicate elements in the sorting linked list]

Input: head = [1,1,2]
Output: [1,2]

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        ListNode* dummy = new ListNode(109);
        ListNode* tail = dummy;
        while(head){
            if(tail->val!=head->val){
                tail->next = head;
                tail = head;
            }
            head = head->next;
        }
        tail->next = nullptr;
        return dummy->next;
    }
};

[86. Separate linked list]

Give you a head node of the linked list and a specific value X. please separate the linked list so that all nodes less than x appear before nodes greater than or equal to X.
You should keep the initial relative position of each node in both partitions.

——Set up two virtual head nodes smallHead bigHead

Then the two nodes go through the needle and make the small and large list

class Solution {
public:
    ListNode* partition(ListNode* head, int x) {//Two virtual head nodes, smallhead and Bighead, are required, and then the two nodes go through the needle to fix the small and large list s,
        ListNode* smallHead = new ListNode(0);
        ListNode* small = smallHead;
        ListNode* bigHead = new ListNode(0);
        ListNode* big = bigHead;
        while(head){
            if(head->val<x){
                small->next = head;
                small = head;
            }
            else{
                big->next = head;
                big = head;
            }
            head = head->next;
        }
        small->next = bigHead->next;//This is the function of bigHead
        big->next = nullptr;
        return smallHead->next;
    }
};

[21. Merge two ordered linked lists]

Merge the two ascending linked lists into a new ascending linked list and return. The new linked list is composed of all nodes of a given two linked lists.

Idea: it's comparison. Note that there are empty points after comparing a list. At this time, the following two while should be added!!!

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* dummy = new ListNode(-1);
        ListNode* tail = dummy;
        if(!l1 and !l2) return nullptr;
        if(!l1 and l2)  return l2;
        if(l1 and !l2)  return l1;
        while(l1 and l2){
            if(l1->val <= l2->val){
                tail->next = l1;
                tail = l1;
                l1 = l1->next;
            }
            else{
                tail->next = l2;
                tail = l2;
                l2 = l2->next;
            }
        }
        while(l1){
            tail->next = l1;
            tail = l1;
            l1 = l1->next;
        }
        while(l2){
            tail->next = l2;
            tail = l2;
            l2 = l2->next;
        }
        tail->next = nullptr; 
        return dummy->next;
    }
};

[328. Parity linked list]

class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        if(head==nullptr) return head;
        ListNode *dummyHead = new ListNode (-1);
        dummyHead->next = head;
        ListNode *evenHead = head->next;//Mark the node of even t
        ListNode *even = evenHead;//Move with even
        while(even!=nullptr && even->next!=nullptr){//Update conditions should be judged well
            head ->next = even ->next;
            head = head ->next;
            even ->next = head ->next;
            even = even ->next;
        }
        head ->next = evenHead;
        return dummyHead->next;
    }
};

[2. Add two numbers]


Idea:
1. Save Val of l1 and l2 with a and b respectively (judge whether they exist or not first)
2. Save carry with t
3.cur to store the current value (perhaps sum is better)
4. Update

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode *dummy = new ListNode(0);
        ListNode *cur = dummy;
        int t = 0;
        while(l1 or l2){
            int a = l1?l1->val:0;
            int b = l2?l2->val:0;
            t = a+b+t;
            cur -> next = new ListNode(t%10);
            t /= 10;
            cur = cur->next;
            if(l1) l1 = l1->next;
            if(l2) l2 = l2->next;
        }
        if(t!=0) cur ->next = new ListNode(t);
        return dummy->next;
    }
};

[445. Adding two numbers II]

——stack + head insertion method

Idea:
Here is to change the direction. It is required not to reverse, so stack is the best. Push all the numbers into the stack, and then take them out and add them in turn. Attention should be paid to carry during calculation. Finally get the answer. It's wonderful. It's a bit like head insertion.

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        stack<int> s1,s2;
        while(l1) {s1.push(l1->val);l1 = l1->next;}
        while(l2) {s2.push(l2->val);l2 = l2->next;}
        int t = 0;//carry
        ListNode *tail = nullptr;//For back reversal
        while(!s1.empty() or !s2.empty() or t!=0){//Attention t= 0 should also be placed as a condition
            int a = s1.empty()?0:s1.top();
            int b = s2.empty()?0:s2.top();
            if(!s1.empty()) s1.pop();
            if(!s2.empty()) s2.pop();
            int cur = (a+b+t)%10;//return val of the linked list
            t = (a+b+t)/10;//Update carry
            ListNode *curnode = new ListNode(cur);//Open a new curnode to put the val of cur
            curnode ->next = tail;//Draw a picture to understand the reversal here, which is very similar to the head interpolation
            tail = curnode;
        }
        return tail;
    }
};

[24. Exchange nodes in linked list in pairs]


FN: node1 CN: node2 n: next

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy = new ListNode(0);
        dummy->next = head;
        ListNode* pre = dummy;
        while(pre->next && pre->next->next){
            ListNode* FN = pre->next;
            ListNode* CN = FN ->next;
            ListNode* n = CN->next;

            CN ->next = FN;
            FN ->next = n;
            pre->next = CN;

            pre = FN;
        } 
        return dummy->next;
    }
};

2. Linked list sorting problem (to be done)

[147. Insert and sort linked list]

[148. Sorting linked list]

3. It's not just a linked list problem

[237. Delete nodes in the linked list]

——Introduce C + + memory management and design principles (not very understood) link

4. Double pointer

[19. Delete the penultimate node of the linked list]

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(-1);
        dummy ->next = head;
        ListNode* fast = dummy;
        ListNode* slow = dummy;
        while(n-- && fast!=nullptr){fast =fast->next;}
        fast = fast->next;
        while(fast!=nullptr){
            fast = fast->next;
            slow = slow->next;
        }
        ListNode* del_node = slow->next;//C + + features, to learn to free memory
        slow->next = del_node->next;
        delete del_node;
        return dummy->next;
    }
};

Topics: Algorithm data structure