LeetCode Linked List Cycle II
阿新 • • 發佈:2018-12-23
Problem
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Note: Do not modify the linked list.
Follow up: Can you solve it without using extra space?
找到連結串列中環的入口節點,不開闢額外空間
Python 實現
# Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
#
# Note: Do not modify the linked list.
#
# Follow up:
# Can you solve it without using extra space?
# author li.hzh
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle (self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
# 假設連結串列中環外節點長度為L, 環內節點長度為C。則有:0 <= L; 0 <= C。例如:
# a - > b - > c - > | d -> e ->f -> g - >(d),此時 L= 3, C = 4。
# 現在考慮有環的情況,現有一快一慢兩個指標,慢的每次走一個節點,快的每次兩個,則有,慢節點進入環,需要L步,
# 此時 fast 應該在環內的 L % C = K 的位置。對應上例,就是 3 % 4 = 3 (d + 3 = g)的位置。因此,從環內看,
# 相聚還需要 C - K = 4 - 3 = 1步。因此,第一次相遇在d + 1 = e的位置。此時,走到環的初始位,需要 C - (C - K) = K = 3步。
# 那麼問題就變成了,怎麼得到這個K。我們簡單思考,當L < C時,顯然L = K。當 L > C 時,我們想象成兩個每次都一步的指標,一個從頭,
# 一個在環內K位行走。當走各走nC步時,環內回到原地。從原點出發的距離環的入口正好還差K步,因此,不論如何,二者必將在入口處相遇。
# 入口位的節點就找到了
if head is None:
return None
slow = faster = head
while faster is not None:
slow = slow.next
if faster.next is not None:
faster = faster.next.next
else:
return None
if slow is faster:
break
if faster is None:
return None
slow = head
while slow is not faster:
slow = slow.next
faster = faster.next
return slow
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
a = ListNode(1)
b = ListNode(2)
a.next = b
c = ListNode(3)
b.next = c
d = ListNode(4)
c.next = d
e = ListNode(5)
d.next = e
f = ListNode(6)
e.next = f
g = ListNode(7)
f.next = g
g.next = d
print(Solution().detectCycle(a))
分析
這個題目著實想了很久,水平有限。還是要求不開闢額外空間。整個的思考過程都寫在註釋上了,因為也是一邊計算,一邊思考,一邊作為記錄的。
如果可以使用額外記憶體,那兩道題都很簡單,整個Set存一下級別,判斷Set是否存在即可。
不使用額外記憶體,還是首先考慮追擊,判斷是否相遇,然後通過數學計算相遇節點的位置特點,最終找到入口。詳見註釋的分析過程。