面試題52:兩個連結串列的第一個公共節點
阿新 • • 發佈:2020-08-21
輸入兩個連結串列,找出它們的第一個公共結點。(注意因為傳入資料是連結串列,所以錯誤測試資料的提示是用其他方式顯示的,保證傳入資料是正確的)
解題思路
- 暴力列舉(O(m*n))
- 輔助棧(兩個棧)
- 雙指標(O(m+n))
上程式碼(C++很香)
法一:暴力列舉
ListNode* FindFirstCommonNodeBL( ListNode* pHead1, ListNode* pHead2) { ListNode* pNode1 = pHead1; ListNode* pNode2 = pHead2; while(pNode1 != nullptr){ pNode2 = pHead2; while(pNode2 != nullptr){ if(pNode1 == pNode2) return pNode1; pNode2 = pNode2->next; } pNode1 = pNode1->next; } return nullptr; }
法二:輔助棧
注意,在判斷棧頂元素的時候,直到棧頂元素不相等時,可能是找到了第一個相等的節點,也可能是沒有相等的節點。
ListNode *FindFirstCommonNode(ListNode *headA, ListNode *headB){ if(headA == nullptr || headB == nullptr) return nullptr; ListNode* p = headA; ListNode* q = headB; stack<ListNode* > stack_a; stack<ListNode* > stack_b; while(p != nullptr){ stack_a.push(p); p = p->next; } while(q != nullptr){ stack_b.push(q); q = q->next; } int sizeA = stack_a.size(); int tmp = 0; while(!stack_a.empty() && !stack_b.empty()){ if(stack_a.top() != stack_b.top()) break; else{ stack_a.pop(); stack_b.pop(); tmp++; } } tmp = sizeA - tmp; p = headA; while(tmp--) p = p->next; return p; }
法三:雙指標(很妙)
這裡先假設連結串列A
頭結點與結點8
的長度 與 連結串列B
頭結點與結點8
的長度相等,那麼就可以用雙指標。
- 初始化:指標
ta
指向連結串列A
頭結點,指標tb
指向連結串列B
頭結點 - 如果
ta == tb
, 說明找到了第一個公共的頭結點,直接返回即可。 - 否則,
ta != tb
,則++ta,++tb
所以現在的問題就變成,如何讓本來長度不相等的變為相等的?
假設連結串列A
長度為a
, 連結串列B
的長度為b
,此時a != b
但是,a+b == b+a
因此,可以讓a+b作為連結串列A的新長度,b+a作為連結串列B的新長度。
// 雙指標法 ListNode* FindFirstCommonNodeDouble(ListNode* pHead1, ListNode* pHead2){ if(pHead1== nullptr || pHead2 == nullptr) return nullptr; ListNode* pNode1 = pHead1; ListNode* pNode2 = pHead2; while(pNode1 != pNode2){ pNode1 = pNode1->next; pNode2 = pNode2->next; if(pNode1 != pNode2){ if(pNode1 == nullptr) pNode1 = pHead2; if(pNode2 == nullptr) pNode2 = pHead1; } } // 走到最後是pNode1 == pNode2 == nullptr // 所以如果有相同的節點,則返回第一個,如果沒有,就最後返回nullptr return pNode1; }