1. 程式人生 > 其它 >[題解]劍指 Offer 52. 兩個連結串列的第一個公共節點(C++)

[題解]劍指 Offer 52. 兩個連結串列的第一個公共節點(C++)

題目

輸入兩個連結串列,找出它們的第一個公共節點。

如下面的兩個連結串列:

在節點 c1 開始相交。

示例 1:

輸入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
輸出:Reference of the node with value = 8
輸入解釋:相交節點的值為 8 (注意,如果兩個列表相交則不能為 0)。從各自的表頭開始算起,連結串列 A 為 [4,1,8,4,5],連結串列 B 為 [5,0,1,8,4,5]。在 A 中,相交節點前有 2 個節點;在 B 中,相交節點前有 3 個節點。

示例2:

輸入:intersectVal= 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
輸出:Reference of the node with value = 2
輸入解釋:相交節點的值為 2 (注意,如果兩個列表相交則不能為 0)。從各自的表頭開始算起,連結串列 A 為 [0,9,1,2,4],連結串列 B 為 [3,2,4]。在 A 中,相交節點前有 3 個節點;在 B 中,相交節點前有 1 個節點。

示例3:

輸入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
輸出:null
輸入解釋:從各自的表頭開始算起,連結串列 A 為 [2,6,4],連結串列 B 為 [1,5]。由於這兩個連結串列不相交,所以 intersectVal 必須為 0,而 skipA 和 skipB 可以是任意值。
解釋:這兩個連結串列不相交,因此返回 null。

注意:

·如果兩個連結串列沒有交點,返回 null.
·在返回結果後,兩個連結串列仍須保持原有的結構。
·可假定整個連結串列結構中沒有迴圈。
·程式儘量滿足 O(n) 時間複雜度,且僅用 O(1) 記憶體。

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

思路

找公共節點,首先想到的是用雜湊表。遍歷listA把所有的節點存入到雜湊表裡,再遍歷listB看有沒有存在於雜湊表中的節點,如果有就返回。
時間複雜度O(m+n),空間複雜度O(m)。

程式碼

/**
 * 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*> s;
        ListNode* p1 = headA, *p2 = headB;
        while(p1){
            s.insert(p1);
            p1 = p1->next;
        }
        while(p2){
            if(s.count(p2)){
                return p2;
            }
            p2 = p2->next;
        }
        return nullptr;
    }
};

改進

這題的另一個思路是雙指標,利用了題中給出的連結串列結構沒有迴圈的條件。用p1和p2分別指向listA和listB,各自遍歷連結串列結束後如果還沒有相遇,就讓p1去遍歷listB,p2去遍歷listA,這次如果遇到p1 == p2就說明要麼指向了第一個公共節點,要麼沒有公共節點(p1和p2均為nullptr)。假設listA和listB分別分解為a+c和b+c,c是它們的公共部分,那麼有3種可能:(1)a == b,p1和p2還沒遍歷完連結串列就相遇了;(2)a != b,p1和p2分別走過的部分是a+c+b和b+c+a,兩者距離一樣,必定相遇;(3)c == 0,p1和p2不會相遇,但是當它們都遍歷完兩個連結串列後均指向nullptr,此時p1 == p2成立。
時間複雜度O(m+n),空間複雜度O(1)。

程式碼

/**
 * 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 || !headB) return nullptr;
        ListNode *p1 = headA, *p2 = headB;
        while(p1 != p2){
            p1 = (p1 == nullptr) ? headB : p1->next;
            p2 = (p2 == nullptr) ? headA : p2->next;
        }
        return p1;
    }
};