1. 程式人生 > >LeetCode演算法題-Intersection of Two Linked Lists(Java實現)

LeetCode演算法題-Intersection of Two Linked Lists(Java實現)

這是悅樂書的第178次更新,第180篇原創

01 看題和準備

今天介紹的是LeetCode演算法題中Easy級別的第37題(順位題號是160)。編寫程式以找到兩個單鏈表交叉的節點。例如:

以下兩個連結串列:

A:       a1→a2
                           ↘
                                c1→c2→c3
                           ↗
B:b1→b2→b3

連結串列A和連結串列B在c1處相交。

注意

如果兩個連結列表根本沒有交集,則返回null。

函式返回後,連結列表必須保留其原始結構。

可以假設整個連結結構中沒有任何環。

程式碼最好在O(n)時間內執行,並且只使用O(1)記憶體。

本次解題使用的開發工具是eclipse,jdk使用的版本是1.8,環境是win7 64位系統,使用Java語言編寫和測試。

02 第一種解法

這兩個單鏈表,也可以看做是兩陣列,找出其中重複元素開始位置的值,最直接的辦法就是上兩層迴圈,外層遍歷連結串列A,內層迴圈遍歷連結串列B,直到遇到相交的節點為止,否則返回空。

特殊情況:當兩連結串列中有一個為空的話,直接返回空。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    if (headA == null || headB == null) {
        return null;
    }
    ListNode B = headB;
    while (headA != null) {
        while (headB != null) {
            if (headA == headB) {
                return headA;
            }
            headB = headB.next;
        }
        headA = headA.next;
        headB = B;
    }
    return null;
}

但是此種解法的時間時間複雜度是O(n^2),最壞的情況是兩連結串列的長度都是n,並且相交的節點在最後位置或者沒有相交的點。

03 第二種解法

先來看個例子,假設A和B兩人要比武,A的功夫等級是10級,B的功夫等級是8級,B覺得這樣比武不公平,就讓A把實力壓制到8級,再去和B比武,此時兩人的功夫等級都是8級,於是開始了一場驚天動地的比武...

回到此題中來,因為無法確定兩個連結串列的長度是否相等,就算兩者有交點,但是起點不一樣,還是會錯過,無法找到交點。這時,我們就需要判斷兩連結串列的長度,重新定義好起點,才能開始遍歷節點。

如果連結串列A長度大於連結串列B的長度,此時連結串列A就需要先向前移動兩者之間長度差值個節點,然後才能和B開始依次遍歷比較,反之B也是如此。

public ListNode getIntersectionNode2(ListNode headA, ListNode headB) {
    int len1 = findLength(headA);
    int len2 = findLength(headB);
    int diff = (len1 >= len2) ? (len1 - len2) : (len2 - len1);
    if (len1 >= len2) {
        while (diff > 0) {
            headA = headA.next;
            diff--;
        }
    } else {
        while (diff > 0) {
            headB = headB.next;
            diff--;
        }
    }
    while (headA != null || headB != null) {
        if (headA == headB) {
            return headA;
        }
        headA = headA.next;
        headB = headB.next;
    }
    return null;
}

public int findLength(ListNode head) {
    int len = 0;
    while (head != null) {
        len += 1;
        head = head.next;
    }
    return len;
}


04 第三種解法

還記得之前那道判斷單鏈表是否有環的題目嗎?沒錯,此題我們也可以藉助環的思路來解題。

當遍歷A連結串列時,如果遍歷到了最後一位節點,此時跳轉到B連結串列的起始節點,然後開始遍歷B連結串列;當遍歷B連結串列時,如果遍歷到了最後一位節點,此時跳轉到A連結串列的起始節點,然後開始遍歷A連結串列。此時就相當於在遍歷一條由連結串列A和連結串列B組合起來的新連結串列,如果此新連結串列存在環,那麼表示兩連結串列是有交點的,如果遍歷完都沒有碰到環,說明兩連結串列是沒有交點的。

public ListNode getIntersectionNode3(ListNode headA, ListNode headB) {
    if (headA == null || headB == null) {
        return null;
    }
    ListNode A = headA;
    ListNode B = headB;
    while (A != B) {
        if (A != null) {
            A = A.next;
        } else {
            A = headB;
        }
        if (B != null) {
            B = B.next;
        } else {
            B = headA;
        }
    }
    return A;
}


05 小結

此題最優解法是第三種解法,其次是第二種,最差的解法是第一種。

演算法專題目前已連續日更超過一個月,演算法題文章37+篇,公眾號對話方塊回覆【資料結構與演算法】、【演算法】、【資料結構】中的任一關鍵詞,獲取系列文章合集。

以上就是全部內容,如果大家有什麼好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支援!