1. 程式人生 > 其它 >打敗演算法 —— 相交連結串列

打敗演算法 —— 相交連結串列

本文參考

出自LeetCode上的題庫 —— 相交連結串列,根據官方的雙指標解法,本文從另一個角度進行分析

https://leetcode-cn.com/problems/intersection-of-two-linked-lists/

相交連結串列問題

給定兩個單鏈表的頭節點 headA 和 headB ,找出並返回兩個單鏈表相交的起始節點。如果兩個連結串列不存在相交節點,返回 null

示例1:
輸入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
輸出:Intersected at '8'

示例 2:
輸入:intersectVal= 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
輸出:Intersected at '2'

示例 3:
輸入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
輸出:null

解題思路

到目前為止已經做了很多雙指標的解法,就不考慮遍歷一遍連結串列,把結點存到連結串列裡再進行判斷的普通做法了。官方提供的雙指標解法很巧妙,假設連結串列A比連結串列B長,那麼兩條連結串列的指標同時開始移動時,連結串列B的指標會率先到達連結串列的末尾。此時,連結串列B的指標下一步從連結串列A的起始位置移動,同理連結串列A的指標到達連結串列末尾後,下一步從連結串列B的起始位置移動。這種做法的本質,類似於填補上了兩條連結串列長度上的差值。

因此,可以有另一種思考方式,仍然假設連結串列A比連結串列B長,連結串列B的指標到達末尾後,計算連結串列A的指標還需要走多少步才會到達末尾,得到計數值cnt。然後兩個連結串列再從頭開始遍歷,只不過連結串列A的指標要提前走好cnt個步數,相當於兩個連結串列的指標從距離相交結點相同距離的起點出發,若相交結點存在,則一定能夠相遇。

雙指標解法

class ListNode:
def __init__(self, x):
self.val = x
self.next = None

class
Solution:
def

get_intersection_node(self, headA: ListNode, headB: ListNode) -> ListNode:
if not (headA and headB):
return None

curr_a = headA
curr_b = headB

#讓較長的一個連結串列首先到達末尾

while curr_a and curr_b:
if curr_a == curr_b:
return curr_a
curr_a = curr_a.next
curr_b = curr_b.next

cnt = 0
if curr_a:
#a連結串列較長,計算a比b長多少

while curr_a:
curr_a = curr_a.next
cnt += 1
#重新從頭開始,讓a事先走比b多出來的步數

curr_a = headA
curr_b = headB
while cnt:
curr_a = curr_a.next
cnt -= 1
elif curr_b:
#b連結串列較長,計算b比a長多少

while curr_b:
curr_b = curr_b.next
cnt += 1
#重新從頭開始,讓b事先走比a多出來的步數

curr_a = headA
curr_b = headB
while cnt:
curr_b = curr_b.next
cnt -= 1
else:
#兩個連結串列一樣長,但是沒有相交的結點

return None

#補充多餘步數後,一起開始移動

while curr_a != curr_b:
curr_a = curr_a.next
curr_b = curr_b.next

if curr_a:
return curr_a
else:
return None