1. 程式人生 > 其它 >劍指offer36--連結串列的第一個公共結點

劍指offer36--連結串列的第一個公共結點

技術標籤:劍指offer連結串列指標資料結構演算法

題目描述

輸入兩個連結串列,找出它們的第一個公共結點。(注意因為傳入資料是連結串列,所以錯誤測試資料的提示是用其他方式顯示的,保證傳入資料是正確的)

思路

思路1:雜湊
map有一個特點,當使用陣列插入方式時,遇到相同的鍵值,會把原來的值給覆蓋,但是可以通過構造一個pair來檢測是否插入成功。
實現:

class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        if (!pHead1||
!pHead2) return nullptr; map<ListNode*,int> m; ListNode* p=pHead1;//先遍歷第一條連結串列將所有結點加入到map中 while (p) { m[p]=p->val; p=p->next; } pair<map<ListNode*, int>::iterator, bool> insert_pair;
//構造一個pair p=pHead2;//再遍歷第二條連結串列 while(p) { insert_pair = m.insert(map<ListNode*, int>::value_type (p, p->val)); if (!insert_pair.second)//如果存在公共結點,這個就不會插入成功,對應這個Pair的第二個引數就是false,那麼這個結點就是第一個公共結點 return p; p=p->next; }
return nullptr; } };

分析:
空間複雜度和時間複雜度都是兩條連結串列的長度和,即都是O(m+n)

思路2:雙指標
用兩個指標分別遍歷2條連結串列兩次:
(假設長度不相等,因為相等的情況太好做了)
第一次都各自走到頭,短的先走到頭,然後重新將其指向長的那條繼續走;長的後走到頭,將其指向短的繼續走。這時候兩個指標走的路是一樣長了,要麼走到公共結點,要麼兩個同時為null

class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        if (!pHead1||!pHead2) return nullptr;
        
        ListNode* p1=pHead1;
        ListNode* p2=pHead2;
        while (p1!=p2)
        {
            p1=p1->next;
            p2=p2->next;
            if (p1!=p2)
            {
            	//短的先開啟了第二輪遍歷
                if (!p1) p1=pHead2;
                if (!p2) p2=pHead1;
            }
            
        }
        return p1;
    }
};

分析:
時間複雜度:最壞的情況是公共結點在末尾,這樣兩條連結串列都要完整遍歷兩次,即O(2m+2n),這樣比較起來雜湊的時間複雜度反而要低,因為只要各遍歷一次。
空間複雜度為O(1)

思路3:雙指標(2)
先遍歷一次兩條連結串列求得其長度差x;
第二次遍歷長的連結串列先跑x步,短的連結串列再開始跑,當兩者相等時就是第一個公共結點。

class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        if (!pHead1||!pHead2) return nullptr;
        //先遍歷求得兩個連結串列的長度
        int a1=0,a2=0;
        ListNode* p1=pHead1;
        ListNode* p2=pHead2;
        while (p1)
        {
            a1++;
            p1=p1->next;
        }
        while (p2)
        {
            a2++;
            p2=p2->next;
        }
        
        
        p1=pHead1;
        p2=pHead2;
        int a=abs(a1-a2);
        //長的先走
        if (a1>a2)
        {
            while (a)
            {
                p1=p1->next;
                a--;
            }
        }
        else{
            while (a)
            {
                p2=p2->next;
                a--;
            }
        }
        //再一起走
        while (p1!=p2)
        {
            p1=p1->next;
            p2=p2->next;
        }
        return p1;
    }
};

時間複雜度和空間複雜度跟思路2其實是一樣的,並且更容易想到,但是程式碼沒有思路2的簡潔