題目鏈接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/
方法一: 暴力法
對鏈表A中的每一個結點ai,遍歷整個鏈表 B 並檢查鏈表 B 中是否存在結點和ai相同。
複雜度分析
時間複雜度 : (mn)。
空間複雜度 : O(1)O(1)。
方法二: 哈希表法
遍歷鏈表 A 並將每個結點的地址/引用存儲在哈希表中。然後檢查鏈表 B 中的每一個結點bi是否在哈希表中。若在,則bi爲相交結點。
複雜度分析
時間複雜度 : O(m+n)O(m+n)。
空間複雜度 : O(m)O(m) 或 O(n)O(n)。
方法三:雙指針法
創建兩個指針 pApA 和 pBpB,分別初始化爲鏈表 A 和 B 的頭結點。然後讓它們向後逐結點遍歷。
當 pApA 到達鏈表的尾部時,將它重定位到鏈表 B 的頭結點 (你沒看錯,就是鏈表 B); 類似的,當 pBpB 到達鏈表的尾部時,將它重定位到鏈表 A 的頭結點。
若在某一時刻 pApA 和 pBpB 相遇,則 pApA/pBpB 爲相交結點。
想弄清楚爲什麼這樣可行, 可以考慮以下兩個鏈表: A={1,3,5,7,9,11} 和 B={2,4,9,11},相交於結點 9。 由於 B.length (=4) < A.length (=6),pBpB 比 pApA 少經過 22 個結點,會先到達尾部。將 pBpB 重定向到 A 的頭結點,pApA 重定向到 B 的頭結點後,pBpB 要比 pApA 多走 2 個結點。因此,它們會同時到達交點。
如果兩個鏈表存在相交,它們末尾的結點必然相同。因此當 pApA/pBpB 到達鏈表結尾時,記錄下鏈表 A/B 對應的元素。若最後元素不相同,則兩個鏈表不相交。
複雜度分析
時間複雜度 : O(m+n)O(m+n)。
空間複雜度 : O(1)O(1)。
下面代碼思路:
我們需要做的事情是,讓兩個鏈表從同距離末尾同等距離的位置開始遍歷。這個位置只能是較短鏈表的頭結點位置。
爲此,我們必須消除兩個鏈表的長度差
指針 pA 指向 A 鏈表,指針 pB 指向 B 鏈表,依次往後遍歷
如果 pA 到了末尾,則 pA = headB 繼續遍歷
如果 pB 到了末尾,則 pB = headA 繼續遍歷
比較長的鏈表指針指向較短鏈表head時,長度差就消除了
如此,只需要將最短鏈表遍歷兩次即可找到位置
聽着可能有點繞,看圖最直觀,鏈表的題目最適合看圖了
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null){
return null;
}
ListNode pA = headA,pB = headB;
while(pA != pB){
pA = pA == null? headB : pA.next;
pB = pB == null? headA : pB.next;
}
return pA;
}
}