Brief Summary of Linked List + LeetCode 142 Linked List Cycle II

Singly Linked List

不能通过 index 在 \(O(1)\) 时间访问元素, 而必须从头开始找, 平均花费 \(O(n)\) 时间.
插入元素时只需要 \(O(1)\) 时间, 而列表则需要移动所有的后继元素.
在删除元素时, 找 next node 很容易, 但是找 previous node 则需要从头开始, 平均需要 \(O(n)\) 时间. 双链表就只需要 \(O(1)\).

Two Pointer Technique

LeetCode 142. Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.
Note: Do not modify the linked list.

Slow pointer 每次移动 1 步, fast pointer 每次移动 2 步, 从 head 同时出发.
记环的入口 index 为 \(e\) (entrance), 第一次相遇时 index 为 \(m\) (meeting), 环的长度为 \(l\) (loop length).
则当 slow pointer 到入口时, fast pointer 比 slow pointer 快了 \(e \bmod l\) 步, 则

\[m = e + [l - (e \bmod l)]. \]

相遇后把 fast pointer 扔掉, 同时让另一个 slow pointer 从 head 开始跑, 则新 slow pointer 到入口时, 比老的慢

\[[(m + e) - e] \bmod l = 0. \]

  • English version

The slow pointer moves 1 step at a time, while the fast pointer moves 2 steps. Let them start at head simultaneously.
Let the index of the entrace of the loop be \(e\), the index of the first meeting point be \(m\), and the length of the loop be \(l\).
Then when the slow pointer arrives at the entrance of the loop, the fast pointer leads it \(e \bmod l\) step(s). We have that

\[m = e + [l - (e \bmod l)]. \]

After first meeting, drop the fast pointer, and let another slow pointer start at head. Then when the new slow pointer arrives at the entrance, the older one leads it

\[[(m + e) - e] \bmod l = 0 \]

step, which means they meet at the entrance.

# 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
        """
        if not head:
            return None        

        slow = head
        fast = head

        while True:
            
            slow = slow.next
            fast = fast.next.next if fast.next else None
            
            if not fast:
                return None
            if slow == fast:
                slow2 = head
                while slow != slow2:
                    slow = slow.next
                    slow2 = slow2.next
                return slow

Tips

  • Always examine if the node is null before you call the next field.
    Getting the next node of a null node will cause the null-pointer error. For example, before we run fast = fast.next.next, we need to examine both fast and fast.next is not null.
if not head:
    return None
  • 添加 dummy head (sentinel) 可以简化操作.

  • Other classic problems
    21 Merge Two Sorted Lists
    138 Copy List with Random Pointer
    206 Reverse Linked List

posted @ 2019-07-05 15:48  resolvent  阅读(252)  评论(0编辑  收藏  举报