1. 程式人生 > 實用技巧 >劍指 Offer 52. 兩個連結串列的第一個公共節點

劍指 Offer 52. 兩個連結串列的第一個公共節點


題目連結

題目描述:


我的題解:

方法一:雙指標法

思路分析:

  • 宣告兩個指標p1,p2 分別指向連結串列A、連結串列B。
  • 然後分別同時逐結點遍歷
  • 當 p1 到達連結串列 headA 的末尾時,重新定位到連結串列 headB 的頭結點;當 p2 到達連結串列 headB 的末尾時,重新定位到連結串列 headA 的頭結點。
  • 如此,當它們相遇時,所指向的結點就是第一個公共結點。
    (p1 p2可以分別遍歷完兩條連結串列。同時開始,將可以保證同時遍歷結束。又因一旦同時指向第一個相交節點時,剩下的節點數相同;故可以保證p1和p2能同時指向到第一個相交節點(即相遇))

程式碼如下:

     public ListNode getIntersectionNode(ListNode headA, ListNode headB) {

        if (headA == null || headB == null) return null;

        ListNode p1 = headA;
        ListNode p2 = headB;
        int change =0; // 重定位到連結串列頭的次數和
        while (p1 != p2) {

            if (p1.next == null) {
                p1 = headB; // 重定位到另一連結串列頭
                change++;
            } else p1 = p1.next;

            if (p2.next == null) {
                p2 = headA; // 重定位到另一連結串列頭
                change++;
            } else p2 = p2.next;


            if (change > 2) return null; // 兩個指標均已遍歷另一條連結串列了
        }
        return p1;
    }

方法二:也是雙指標,但先求連結串列長度,再同時移動

思路分析:

  • 宣告兩個指標p1,p2 分別指向連結串列A、連結串列B。
  • 稍後做一定的處理後 會同時移動兩個指標。
  • 此題中,可以保證兩指標最後同時到達連結串列尾,那麼,也就可以保證同時到達相交結點(如果有的話)。
  • 那麼,如何保證呢?分別求出兩條連結串列的長度,然後,讓長連結串列對應的指標,先走幾步(步數為多出來的節點數)。
  • 做完上一步的處理後,p1和p2再同時移動,便可同時到達連結串列尾,自然就可以保證同時到達相交節點了(如果有的話)。

程式碼如下:

     public ListNode getIntersectionNode(ListNode headA, ListNode headB) {

        ListNode p1 = headA;
        ListNode p2 = headB;
        int len1 = getLength(headA);
        int len2 = getLength(headB);

        int different = len1 - len2;
        // 長的指標,先走different步
        if (different > 0) {    // headA 長
            for (int i = different; i > 0; i--) {
                p1 = p1.next;
            }
        } else {    // headB長 或 同樣長(different=0,不進for迴圈了)
            for (int i = -different; i > 0; i--) {
                p2 = p2.next;
            }
        }

        // 接著, p1,p2同時移動。當 p1 p2指向同一節點時,該節點即為題目所求的相交節點
        while (p1!=null && p2!=null && p1 != p2) {
            p1 = p1.next;
            p2 = p2.next;
        }

        return p1;
    }

    private int getLength(ListNode head) {
        int cnt = 0;
        for (ListNode tmp = head; tmp !=null ; tmp = tmp.next) {
            cnt++;
        }
        return cnt;
    }