本文正在參加「Python主題月」,詳情查看 活動連接html
這是 LeetCode 上的 劍指 Offer 52. 兩個鏈表的第一個公共節點 ,難度爲 簡單。node
Tag : 「鏈表」git
輸入兩個鏈表,找出它們的第一個公共節點。github
以下面的兩個鏈表:markdown
在節點 c1 開始相交。數據結構
示例 1: app
輸入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
輸出:Reference of the node with value = 8
輸入解釋:相交節點的值爲 8 (注意,若是兩個列表相交則不能爲 0)。從各自的表頭開始算起,鏈表 A 爲 [4,1,8,4,5],鏈表 B 爲 [5,0,1,8,4,5]。在 A 中,相交節點前有 2 個節點;在 B 中,相交節點前有 3 個節點。
複製代碼
示例 2: oop
輸入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
輸出:Reference of the node with value = 2
輸入解釋:相交節點的值爲 2 (注意,若是兩個列表相交則不能爲 0)。從各自的表頭開始算起,鏈表 A 爲 [0,9,1,2,4],鏈表 B 爲 [3,2,4]。在 A 中,相交節點前有 3 個節點;在 B 中,相交節點前有 1 個節點。
複製代碼
示例 3: post
輸入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
輸出:null
輸入解釋:從各自的表頭開始算起,鏈表 A 爲 [2,6,4],鏈表 B 爲 [1,5]。因爲這兩個鏈表不相交,因此 intersectVal 必須爲 0,而 skipA 和 skipB 能夠是任意值。
解釋:這兩個鏈表不相交,所以返回 null。
複製代碼
注意:ui
一個樸素的解法天然是兩層枚舉,逐個檢查哪一個節點相同。
Java 代碼:
public class Solution {
public ListNode getIntersectionNode(ListNode a, ListNode b) {
for (ListNode h1 = a; h1 != null ; h1 = h1.next) {
for (ListNode h2 = b; h2 != null ; h2 = h2.next) {
if (h1 == h2) return h1;
}
}
return null;
}
}
複製代碼
Python 3 代碼:
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
h1 = headA
while h1:
h2 = headB
while h2:
if h1 == h2:
return h1
h2 = h2.next
h1 = h1.next
複製代碼
這是一種「從後往前」找的方式。
將兩條鏈表分別壓入兩個棧中,而後循環比較兩個棧的棧頂元素,同時記錄上一位棧頂元素。
當遇到第一個不一樣的節點時,結束循環,上一位棧頂元素便是答案。
Java 代碼:
public class Solution {
public ListNode getIntersectionNode(ListNode a, ListNode b) {
Deque<ListNode> d1 = new ArrayDeque<>(), d2 = new ArrayDeque<>();
while (a != null) {
d1.add(a);
a = a.next;
}
while (b != null) {
d2.add(b);
b = b.next;
}
ListNode ans = null;
while (!d1.isEmpty() && !d2.isEmpty() && d1.peekLast() == d2.peekLast()) {
ans = d1.pollLast();
d2.pollLast();
}
return ans;
}
}
複製代碼
Python 3 代碼:
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
d1, d2 = deque([]), deque([])
while headA:
d1.append(headA)
headA = headA.next
while headB:
d2.append(headB)
headB = headB.next
ans = None
while d1 and d2 and d1[-1] == d2[-1]:
ans = d1.pop()
d2.pop()
return ans
複製代碼
這是一種「從前日後」找的方式。
使用 Set
數據結構,先對某一條鏈表進行遍歷,同時記錄下來全部的節點。
而後在對第二鏈條進行遍歷時,檢查當前節點是否在 Set
中出現過,第一個在 Set
出現過的節點便是交點。
Java 代碼:
public class Solution {
public ListNode getIntersectionNode(ListNode a, ListNode b) {
Set<ListNode> set = new HashSet<>();
while (a != null) {
set.add(a);
a = a.next;
}
while (b != null && !set.contains(b)) b = b.next;
return b;
}
}
複製代碼
Python 3 代碼:
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
hashSet = set()
while headA:
hashSet.add(headA)
headA = headA.next
while headB and headB not in hashSet:
headB = headB.next
return headB
複製代碼
因爲兩條鏈表在相交節點後面的部分徹底相同,所以咱們能夠先對兩條鏈表進行遍歷,分別獲得兩條鏈表的長度,並計算差值 d
。
讓長度較長的鏈表先走 d
步,而後兩條鏈表同時走,第一個相同的節點便是節點。
Java 代碼:
public class Solution {
public ListNode getIntersectionNode(ListNode a, ListNode b) {
int c1 = 0, c2 = 0;
ListNode ta = a, tb = b;
while (ta != null && c1++ >= 0) ta = ta.next;
while (tb != null && c2++ >= 0) tb = tb.next;
int d = c1 - c2;
if (d > 0) {
while (d-- > 0) a = a.next;
} else if (d < 0) {
d = -d;
while (d-- > 0) b = b.next;
}
while (a != b) {
a = a.next;
b = b.next;
}
return a;
}
}
複製代碼
Python 3 代碼:
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
c1 = c2 = 0
ta, tb = headA, headB
while ta:
ta = ta.next
c1 += 1
while tb:
tb = tb.next
c2 += 1
d = c1 - c2
if d > 0:
while d:
headA = headA.next
d -= 1
elif d < 0:
d = -d
while d:
headB = headB.next
d -= 1
while headA != headB:
headA = headA.next
headB = headB.next
return headA
複製代碼
這是「差值法」的另一種實現形式,原理一樣利用「兩條鏈表在相交節點後面的部分徹底相同」。
咱們令第一條鏈表相交節點以前的長度爲 a
,第二條鏈表相交節點以前的長度爲 b
,相交節點後的公共長度爲 c
(注意 c
可能爲
,即不存在相交節點)。
分別對兩條鏈表進行遍歷:
若是存在交點:第一條鏈表首次到達「第一個相交節點」的充要條件是第一條鏈表走了 步,因爲兩條鏈表同時出發,而且步長相等,所以當第一條鏈表走了 步時,第二條鏈表一樣也是走了 步,即 第二條一樣停在「第一個相交節點」的位置。
若是不存在交點:二者會在走完 以後同時變爲 ,退出循環。
Java 代碼:
public class Solution {
public ListNode getIntersectionNode(ListNode a, ListNode b) {
ListNode ta = a, tb = b;
while (ta != tb) {
ta = ta == null ? b : ta.next;
tb = tb == null ? a : tb.next;
}
return ta;
}
}
複製代碼
Python 3 代碼:
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
ta, tb = headA, headB
while ta != tb:
ta = headB if not ta else ta.next
tb = headA if not tb else tb.next
return ta
複製代碼
這是咱們「刷穿 LeetCode」系列文章的第 No.劍指 Offer 52
篇,系列開始於 2021/01/01,截止於起始日 LeetCode 上共有 1916 道題目,部分是有鎖題,咱們將先把全部不帶鎖的題目刷完。
在這個系列文章裏面,除了講解解題思路之外,還會盡量給出最爲簡潔的代碼。若是涉及通解還會相應的代碼模板。
爲了方便各位同窗可以電腦上進行調試和提交代碼,我創建了相關的倉庫:github.com/SharingSour… 。
在倉庫地址裏,你能夠看到系列文章的題解連接、系列文章的相應代碼、LeetCode 原題連接和其餘優選題解。