1. 程式人生 > >[劍指Offer] 23_連結串列中環的入口節點

[劍指Offer] 23_連結串列中環的入口節點

題目

如果一個連結串列中包含環,如何找出環的入口節點?

例:

1->2->3->4->5->6
    個__________|


思路

  1. 快慢指標相遇時找到環,並算出環長度,然後用一組間隔環長的雙指標從頭遍歷連結串列,相遇時即為入口。
    1. 時間複雜度:O(n),最差情況入口在頭節點,遍歷2次連結串列。
    2. 空間複雜度:O(1)
  2. 如果連結串列有環,那麼遍歷列表將得到一個周期函式。LN(a + b - a) = LN(a + b + nT - a) T為環的長度,a為環之前的長度,b為環內走過的長度。
    此題即求a的值。雙指標遍歷Ps Pf,使Pf2倍快於Ps,那麼總有Pf == Ps,的時候此時Ps = a + b; Pf = 2a + 2b;nT = a + b。因此,當Ps再走a步時,LN(Ps = a + b + a) =LN(a),此時一個從頭出發的節點也正好走到LN(a)。此節點即為入口。
    1. 時間複雜度:O(n),比思路1快,只需要遍歷1次連結串列。
    2. 空間複雜度: O(1)

程式碼

思路2:

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
def entry_node_in_list_loop(head):
    """    
    :param head: head
    :return: entry node
    """
    pos = None
slow = fast = head while slow and fast and fast.next: slow = slow.next fast = fast.next.next if slow is fast: pos = head while pos is not slow: pos = pos.next slow = slow.next break return pos

思考

思路1容易想到,也比較直觀,但是沒有思路2快。思路2需要數學抽象方便理解。
LeetCode上有同樣的題目,可以測試。

142. 環形連結串列 II

題目

給定一個連結串列,返回連結串列開始入環的第一個節點。 如果連結串列無環,則返回 null。

為了表示給定連結串列中的環,我們使用整數 pos 來表示連結串列尾連線到連結串列中的位置(索引從 0 開始)。 如果 pos 是 -1,則在該連結串列中沒有環。

說明:不允許修改給定的連結串列。

示例 1:

輸入:head = [3,2,0,-4], pos = 1
輸出:tail connects to node index 1
解釋:連結串列中有一個環,其尾部連線到第二個節點。
Alt

示例 2:

輸入:head = [1,2], pos = 0
輸出:tail connects to node index 0
解釋:連結串列中有一個環,其尾部連線到第一個節點。

alt

示例 3:

輸入:head = [1], pos = -1
輸出:no cycle
解釋:連結串列中沒有環。

alt

進階:
你是否可以不用額外空間解決此題?