- 任務
- 24. 兩兩交換連結串列中的節點
- 思路
- 19.刪除連結串列的倒數第N個節點
- 思路
- 面試題 02.07. 連結串列相交
- 思路
- 142.環形連結串列II
- 思路
- 24. 兩兩交換連結串列中的節點
- 總結
任務
24. 兩兩交換連結串列中的節點
給你一個連結串列,兩兩交換其中相鄰的節點,並返回交換後連結串列的頭節點。你必須在不修改節點內部的值的情況下完成本題(即,只能進行節點交換)。
思路
這是一道模擬的題,修改的指標較多,較複雜,需要弄清楚修改的順序,細心的一步步修改。但是大體的思路還是不變,引入了虛擬節點,注意單次迴圈中的節點指標域變化。
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode()
dummy.next = head
cur = dummy
while cur and cur.next and cur.next.next:
oldCurNext = cur.next
oldCurNextNextNext = cur.next.next.next
cur.next = cur.next.next
cur.next.next = oldCurNext
oldCurNext.next = oldCurNextNextNext
cur =cur.next.next
return dummy.next
19.刪除連結串列的倒數第N個節點
思路
兩個人同樣的速度勻速跑步,初始時B在A前面n米,此時兩人同時跑步,則B到達終點時,A距離終點也是n米。類比刪除倒數第n個的節點,需要slow和fast指標,fast先走n步,然後slow,fast同時走,則fast到達終點時,slow指向的就是倒數第n個節點。為了刪除該節點,則應該找到待刪除節點的前一個節點的引用,因此fast開始時先走n+1步,此時再按照剛才的邏輯,slow就會指向待刪除節點的前一個節點,修改其指標域即可。此外,該題限制了n的正確性1 <= n <= size,因此不需要邊界處理錯誤的情況。
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy = ListNode()
dummy.next = head
slow,fast = dummy,dummy
while n:
fast=fast.next
n-=1
fast = fast.next
while fast:
slow = slow.next
fast = fast.next
slow.next = slow.next.next
return dummy.next
面試題 02.07. 連結串列相交
給你兩個單連結串列的頭節點 headA 和 headB ,請你找出並返回兩個單連結串列相交的起始節點。如果兩個連結串列沒有交點,返回 null。
思路
與上面刪除倒數第n個節點有點類似,先分別遍歷兩個連結串列,得到長度差異delta,此時知道哪個連結串列長哪個連結串列短,或者相同,類似之前的邏輯,長的先跑delta步,此時兩個一起跑,則第一次遇到時就是它們的相交節點,如果短連結串列都遍歷完了還沒有遇到,說明兩個連結串列不相交。
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
cur = headA
delta = 0
while cur:
cur = cur.next
delta+=1
cur = headB
while cur:
cur = cur.next
delta-=1
longerListPointer = headA if delta >0 else headB
shorterListPointer = headA if longerListPointer==headB else headB
delta = abs(delta)
while delta:
longerListPointer = longerListPointer.next
delta-=1
while shorterListPointer:
if longerListPointer == shorterListPointer:
return longerListPointer
longerListPointer= longerListPointer.next
shorterListPointer = shorterListPointer.next
return None
142.環形連結串列II
給定一個連結串列的頭節點 head ,返回連結串列開始入環的第一個節點。 如果連結串列無環,則返回 null。
如果連結串列中有某個節點,可以透過連續跟蹤 next 指標再次到達,則連結串列中存在環。 為了表示給定連結串列中的環,評測系統內部使用整數 pos 來表示連結串列尾連線到連結串列中的位置(索引從 0 開始)。如果 pos 是 -1,則在該連結串列中沒有環。注意:pos 不作為引數進行傳遞,僅僅是為了標識連結串列的實際情況。
不允許修改 連結串列。
思路
- 快慢指標相遇判斷是否有環(是否相遇,之所以有環時一定相遇是因為它們的速度差為1個單位,不會發生快指標跳過慢指標的情況)。
- 入口節點
- 方法一:相遇後,讓其中一個節點從頭走,然後另一個節點從當前位置走,再次相遇即是入口節點(需要畫圖用等式證明,不是很好想到,而且暫時沒有理解為什麼快指標追上慢指標至少需要一圈)
- 方法二:這個方法利用雜湊表來儲存已經訪問過的節點,檢測到第一個重複訪問的節點即為環的入口節點。 (好理解,但空間複雜度O(n))
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow,fast = head,head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
slow = head
while slow!=fast:
slow = slow.next
fast = fast.next
return slow
return None
總結
今天起的太早出門,狀態很差,抽時間把今天的題再思考和做一下。今天主要學到的有以下幾點。
- 連結串列中修改指標(插入,刪除)類似題目的核心是,弄清楚一次迴圈中需要修改哪些指標域,以及修改順序。快慢指標可以
- 快慢指標在連結串列中的應用,可以讓快指標先走n步然後兩個同時走,這裡有個不變數就是它們的delta,此後當到達終點後,就有另一個等式,即終點離slow節點的距離就是n步
;另外,快慢指標還可以彌補兩個不同相交連結串列的行走差距 - 快慢指標在環形連結串列入口節點的應用,後續需要思考下為什麼fast指標至少跑一圈才能追上slow