1. 程式人生 > 實用技巧 >面試題52:兩個連結串列的第一個公共節點

面試題52:兩個連結串列的第一個公共節點

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

解題思路

  • 暴力列舉(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的長度相等,那麼就可以用雙指標。

  1. 初始化:指標ta指向連結串列A頭結點,指標tb指向連結串列B頭結點
  2. 如果ta == tb, 說明找到了第一個公共的頭結點,直接返回即可。
  3. 否則,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;
}