|
| 1 | +class Solution(object): |
| 2 | + """ |
| 3 | + 原理:首先初始化快指针 fast = head.next.next 和 slow = head.next, |
| 4 | + 此时快指针走的路长为2, m慢指针走的路长为1,之后令快指针每次走两步, |
| 5 | + 慢指针每次走一步,这样快指针走的路长始终是慢指针走的路长的两倍, |
| 6 | + 若不存在环,直接返回None, |
| 7 | + 若存在环,则 fast 与 slow 肯定会在若干步之后相遇; |
| 8 | +
|
| 9 | + 性质1: |
| 10 | + 设从head需要走 a 步到达环的入口,如果环存在的话, |
| 11 | + 再走 b 步可以再次到达该入口(即环的长度为b), |
| 12 | + 如果存在环的话,上述描述的 快指针 fast 和 |
| 13 | + 慢指针slow 必然会相遇,且此时slow走的路长 |
| 14 | + 小于 a + b(可以自行证明),设其为 a + x, |
| 15 | + 当快慢指针相遇时,快指针已经至少走完一圈环了, |
| 16 | + 不妨设相遇时走了完整的m圈(m >= 1),有: |
| 17 | +
|
| 18 | + 快指针走的路长为 a + mb + x |
| 19 | + 慢指针走的路长为 a + x |
| 20 | +
|
| 21 | + 由于快指针fast 走的路长始终是慢指针的 2倍,所以: |
| 22 | +
|
| 23 | + a + mb + x = 2(a + x) |
| 24 | +
|
| 25 | + 化简可得: |
| 26 | +
|
| 27 | + a = mb - x ------------- (*) |
| 28 | +
|
| 29 | + 当快指针与慢指针相遇时,由于 <性质1> 的存在, |
| 30 | + 可以在链表的开头初始化一个新的指针, |
| 31 | + 称其为 detection, 此时 detection 距离环的入口的距离为 a, |
| 32 | +
|
| 33 | + 此时令 detection 和 fast 每次走一步, |
| 34 | + 会发现当各自走了 a 步之后,两个指针同时到达了环的入口,理由分别如下: |
| 35 | +
|
| 36 | + detection不用说了,走了a步肯定到刚好到入口 |
| 37 | + fast已经走过的距离为 a + mb + x,当再走 a 步之后, |
| 38 | + fast走过的总距离为 2a + mb + x,带入性质1的(*)式可得: |
| 39 | + 2a + mb + x = a + 2mb,会发现,fast此时刚好走完了 |
| 40 | + 整整 2m 圈环,正好处于入口的位置。 |
| 41 | +
|
| 42 | + 基于此,我们可以进行循环,直到 detection 和 |
| 43 | + fast 指向同一个对象,此时指向的对象恰好为环的入口。 |
| 44 | +
|
| 45 | + """ |
| 46 | + |
| 47 | + def detectCycle(self, head): |
| 48 | + """ |
| 49 | + :type head: ListNode |
| 50 | + :rtype: ListNode |
| 51 | + """ |
| 52 | + # 首先初始化快指针和慢指针,确保快指针走的路的长度是慢指针长度的2倍 |
| 53 | + if head and head.next: |
| 54 | + fast = head.next.next |
| 55 | + slow = head.next |
| 56 | + else: |
| 57 | + return None # 说明无环 |
| 58 | + |
| 59 | + # 进行循环,首先让快指针和慢指针第一次相遇 |
| 60 | + while fast: |
| 61 | + if fast != slow: |
| 62 | + |
| 63 | + # 快指针走两步 |
| 64 | + if fast.next: |
| 65 | + fast = fast.next.next |
| 66 | + else: |
| 67 | + return None # 说明无环 |
| 68 | + |
| 69 | + # 慢指针走一步 |
| 70 | + slow = slow.next |
| 71 | + else: |
| 72 | + detection = head |
| 73 | + while detection != slow: # 此时由于slow和fast是一样的,用哪个都行 |
| 74 | + slow = slow.next |
| 75 | + detection = detection.next |
| 76 | + |
| 77 | + return detection |
| 78 | + |
| 79 | +''' |
| 80 | +题: |
| 81 | +输入:head = [3,2,0,-4], pos = 1 |
| 82 | +输出:true |
| 83 | +解释:链表中有一个环,其尾部连接到第二个节点。 |
| 84 | +
|
| 85 | +注: 不允许修改给出的链表 |
| 86 | +
|
| 87 | +解: |
| 88 | +快慢指针 |
| 89 | +''' |
0 commit comments