Linked list of the second day of data structure

Posted by jonwondering on Wed, 12 Jan 2022 19:12:58 +0100

Day 2 - linked list

In fact, the linked list is relatively simple. For a data field and a pointer field, there are only a few common solutions, such as double pointers. But since I am a Java to C + +, the difficulty for me is to remember to release the space for application. So practice and record.

Remove linked list elements

Force buckle original question

This problem is not difficult. The only problem is that you need to return a new head node when deleting the first node. A reasonable method is to set up a unified deletion operation of the virtual head node, so that in the end, you only need to return the pointing node of the virtual head node.

The code is as follows:

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* h = new ListNode(0); // Virtual head node
        h->next = head;
        ListNode* p = h;
        while (p->next != NULL) {
            if (p->next->val == val) {
                ListNode* tmp = p->next;
                p->next = p->next->next;
                delete tmp; // Note that this is different from Java. You need to read the delete node and delete it manually
            }
            else
            {
                p = p->next;
            }
        }
        head = h->next;
        delete h; // Delete virtual header node
        return head;
    }
};

Flip linked list

Force buckle original question

Flipping the linked list is indeed a conventional problem. Yes, make three nodes to record the current node, the next node and the previous node respectively, and then flip them one by one.

The code is as follows:

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* pre = NULL;
        ListNode* tmp;
        ListNode* cur = head;
        while (cur)
        {
            tmp = cur->next; // Save next node
            cur->next = pre; // Flip
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
};

Exchange the nodes of the linked list in pairs

Force buckle original question

This problem is still a little difficult, because the single linked list needs to maintain the front and back connections and records, and the pairwise exchange determines the need for mediation if the exchange is to be completed. In this case, consider adding a virtual head node. Take V - > 1 - > 2 - > 3 - > L as an example to illustrate our exchange process. First, record that the nodes to be disassembled V - > next and V - > next - > next - > next are t1 and t2 respectively.

Step 1 connect v and 2

List structure after operation: V - > 2

At this time, record t1 is 1

Record t2 as 3 - > L

Step 2 connect 2 and t1

Completed linked list structure: V - > 2 - > 1

There is also a record t2:3 - > L

Step 3 connect t1 and t2

Finished linked list structure: V - > 2 - > 1 - > 3 - > L

Then we move the pointer to V back two items.

The code is as follows:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* h = new ListNode(0); // Set a virtual header node
        h->next = head;
        ListNode* cur = h;
        while (cur->next != NULL && cur->next->next != NULL) {
            ListNode* t1 = cur->next; // Record temporary nodes
            ListNode* t2 = cur->next->next->next; // Record temporary nodes

            cur->next = cur->next->next;    // Step 1
            cur->next->next = t1;          // Step 2
            cur->next->next->next = t2;   // Step 3

            cur = cur->next->next; // cur moves two bits
        }
        return h->next;
    }
};

Delete the penultimate node of the linked list

A simple problem, because the linked list is not like the sequential list, it can directly check the position, so it needs the double pointer method to find the position. The specific operation is to move the fast pointer N steps, and then move the fast pointer back at the same time. When the fast pointer comes to the end, just delete the slow pointer directly. Note here that if N is the table length, you need to delete the header node.

The code is as follows:

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* fast = head;
        ListNode* slow = head;
        int k = 1, s = n; // Here, k records the length of the table and s is used to temporarily store the steps to be taken
        if (head == nullptr)
        {
            return nullptr;
        }
        while (fast->next!=nullptr)
        {
            if (s == 0) // When the distance difference between fast and slow pointers is n, the two pointers go together
            {
                slow = slow->next;
                fast = fast->next;
            }
            else // Otherwise, quickly move the pointer back and record the step length
            {
                fast = fast->next;
                s--;
            }
            k++;
        }
        if (k == n) // Special handling deletes the first element
        {
            ListNode* tmp = head->next;
            delete head;
            return tmp;
        }
        else
        {
            ListNode* tmp = slow->next;
            slow->next = tmp->next;
            delete tmp;
            return head;
        }
    }
};

Linked list intersection

Force buckle original question

If two linked lists intersect, the pointers of the two tables must be equal from the beginning to the end of a node. Therefore, we consider aligning the ends of the two linked lists first, and then calculate the length difference k of the two linked lists. Let the long linked list pointer go k steps first, and then move at the same time. In this way, the node with equal pointers is the intersection.

The code is as follows:

class Solution {
public:
    ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
        ListNode* ap = headA;
        ListNode* bp = headB;
        int lenA = 0, lenB = 0;
        int k = 0;
        while (ap != nullptr) // Length of A linked list
        {
            lenA++;
            ap = ap->next;
        }
        while (bp != nullptr) // Length of B linked list
        {
            lenB++;
            bp = bp->next;
        }
        ap = headA;
        bp = headB;
        if (lenA > lenB) // Find the long list and let him go first
        {
            k = lenA - lenB;
            while (k != 0)
            {
                ap = ap->next;
                k--;
            }
            while (ap != nullptr && bp != nullptr)
            {
                if (ap == bp)
                {
                    return ap;
                }
                ap = ap->next;
                bp = bp->next;
            }
        }
        else
        {
            k = lenB - lenA;
            while (k != 0)
            {
                bp = bp->next;
                k--;
            }
            while (ap != nullptr && bp != nullptr)
            {
                if (ap == bp)
                {
                    return ap;
                }
                ap = ap->next;
                bp = bp->next;
            }
        }
        return nullptr;
    }
};

Circular linked list

Force buckle original question

I'm not good at this kind of problem. Although the essence is still double pointers, the start and end conditions are not so intuitive, so we can draw pictures and try to understand them.

First of all, how to know if the linked list has a ring

Since double hands are two hands fast and slow, let's consider two people running on a track. If one person always runs faster than another, then if the track is circular, over time he will catch up with the slower person. Otherwise they will never meet again. At this time, we know the judgment condition that the linked list has a ring: the fast and slow pointer meets before the fast pointer reaches the exit.

Then the entrance of the ring

To be honest, I really didn't have a clue at first, but if you draw an example on paper and try to simulate the situation yourself, you will find that because the fast pointer enters the ring first, it will actually cycle in the ring and wait for the slow pointer. At this time, the slow pointer enters the ring again, and the distance between the node it meets and the entrance of the ring must be the length in front of the ring% the size of the ring

At this time, we start from the encounter node. One pointer is set as the chain header and the other points to the encounter node. Both move one step at a time. When we meet again, we get the entrance of the ring.

The code is as follows:

class Solution {
public:
    ListNode* detectCycle(ListNode* head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast != nullptr && fast->next != nullptr)
        {
            slow = slow->next; // Take two steps quickly and one step slowly
            fast = fast->next->next;
            if (fast == slow) // The ring resets a pointer position, and then both take only one step to find the entrance
            {
                fast = head;
                while (fast != slow)
                {
                    fast = fast->next;
                    slow = slow->next;
                }
                return slow;
            }
        }
        return nullptr;
    }
};

Topics: data structure leetcode linked list