Sword finger offer: 37 the first common node of two linked lists (note)

Posted by damonlee on Sat, 30 Oct 2021 09:43:10 +0200

Enter two linked lists and find their first common node.

As shown in the following two linked lists:

The intersection begins at node c1.

Example 1:

Input: intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
Output: Reference of the node with value = 8
Input explanation: the value of intersection node is 8 (note that if two lists intersect, it cannot be 0). Starting from their respective headers, linked list A is [4,1,8,4,5], and linked list B is [5,0,1,8,4,5]. In A, there are 2 nodes before the intersection node; In B, there are 3 nodes before the intersection node.

Example   2:

Input: intersectVal  = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
Output: Reference of the node with value = 2
Input explanation: the value of intersection node is 2 (note that if two lists intersect, it cannot be 0). Starting from the respective header, linked list A is [0,9,1,2,4], and linked list B is [3,2,4]. In A, there are 3 nodes before the intersection node; In B, there is 1 node before the intersection node.

Example   3:

Input: intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
Output: null
Input explanation: starting from the respective header, linked list A is [2,6,4], and linked list B is [1,5]. Because the two linked lists do not intersect, intersectVal must be 0, and skipA and skipB can be any value.
Explanation: the two linked lists do not intersect, so null is returned.

be careful:

If two linked lists have no intersection, null is returned
After returning the results, the two linked lists must still maintain their original structure.
It can be assumed that there is no loop in the whole linked list structure.
The program shall meet the O(n) time complexity as much as possible, and only use O(1) memory.

  Method 1: hash set method  

To determine whether two linked lists intersect, you can use a hash set to store linked list nodes.

Code language: cpp

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        unordered_set<ListNode *> q;
        ListNode *tmp = headA;
        while(tmp!=nullptr){    //First, traverse the linked list headA, and add each node in the linked list headA to the hash set
            q.insert(tmp);
            tmp = tmp->next;
        }
        tmp = headB;
        while(tmp!=nullptr){    //Traverse the linked list headB. For each node traversed, judge whether the node is in the hash set
            if(q.count(tmp)){   //If the current node is in the hash set, the following nodes are in the hash set, that is, all nodes starting from the current node are the common nodes of the two linked lists
                return tmp;
            }
            tmp = tmp->next;
        }
        return nullptr;
    }
};

forty-five  /  forty-five   Pass test cases

Status: passed

Execution time:   52 ms

Memory consumption:   16.8 MB

Time complexity: O(m+n), where m   And n   Is the length of the linked list headA and headB respectively. You need to traverse the two linked lists once each.

Spatial complexity: O(m), where m is the length of the linked list headA. You need to use a hash set to store all nodes in the linked list headA.

Method 2:   Double finger needling

Code language: cpp

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA == nullptr || headB == nullptr){   //Only when the linked lists headA and headB are not empty can the two linked lists intersect
            return nullptr;
        }
        ListNode *pA = headA;
        ListNode *pB = headB;
        while(pA != pB){    //Each operation needs to update the pointers pA and pB at the same time (when the pointers pA and pB point to the same node or are empty, return the node they point to or null)
            pA = (pA == nullptr) ? headB : pA->next;    //If the pointer pA is not empty, move the pointer pA to the next node; If the pointer pB is not empty, move the pointer pB to the next node
            pB = (pB == nullptr) ? headA : pB->next;    //If the pointer pA is empty, move the pointer pA to the head node of the linked list headB; If the pointer pB is empty, move the pointer pB to the head node of the linked list headA
        }
        return pA;
    }
};

forty-five  /  forty-five   Pass test cases

Status: passed

Execution time:   40 ms

Memory consumption:   14.1 MB

Time complexity: O(m+n), where m   And n   Is the length of the linked list headA and headB respectively. Two pointers traverse two linked lists at the same time, and each pointer traverses two linked lists once each.

Space complexity: O(1).

Method 3: speed pointer  

Code language: cpp  

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        //Get the length of the two linked lists
        int Alength = GetListLength(headA);
        int Blength = GetListLength(headB);
        int lenthDif = Alength - Blength;   //Difference between the lengths of two linked lists
        ListNode *pheadlong = headA;
        ListNode *pheadshort = headB;
        if(lenthDif < 0){
            lenthDif = Blength - Alength;
            pheadlong = headB;
            pheadshort = headA;
        }
        for(int i = 0; i < lenthDif; i++)   //Let the long linked list go more (long short) distance first
            pheadlong = pheadlong->next;
        while(pheadshort != pheadlong){ //The long and short linked lists are traversed at the same time until the first public node is encountered
            if((pheadshort != nullptr)&&(pheadlong != nullptr)){
                pheadlong = pheadlong->next;
                pheadshort = pheadshort->next;
            }
            else
                return nullptr;
        }
        return pheadshort;
    }
    unsigned int GetListLength(ListNode* pHead){    //Get linked list length function
        unsigned int nlength = 0;
        ListNode* pNode = pHead;
        while(pNode != nullptr){
            ++nlength;
            pNode = pNode->next;
        }
        return nlength;
    }
};

  forty-five  /  forty-five   Pass test cases

Status: passed

Execution time:   36 ms

Memory consumption:   14.1 MB

Topics: C++ data structure linked list