0%

机试-含环链表相关

​ 在含环的问题中,存在一些关键性的结论,在解决问题时非常有帮助,下面是一些相关的总结。

1.判断链表是否有环

​ 结论:一个速度为1的low指针和一个速度为2的fast指针同时从头向前走,如果其中fast指针为None,那么则为无环,如果两个只能指向的元素相等,那么链表有环。

2.判断链表的环入口节点

​ 结论:函数一样的双指针进行遍历,如果fast指针为None,那么则为无环。如果两个指针指向的的元素相同,那么这个节点到链表入口点的长度链表头到链表入口点的长度相等。

推导过程:

​ 设链表头到入口节点的长度为a

​ 链表入口节点到相遇节点的长度为b

​ 相遇节点到链表入口节点的长度为c

​ 那么因为fast的速度为2,low的速度为1,因此可以认为low入环时走在前面,每次fast和low之间的距离缩小1,因此,必定会在第一圈完成之前相遇。所以有

​ low 在环内位置: (a+b)-a mod (b+c) -> b mod (b+c)

​ fast 在环内位置:2(a+b)-a mod (b+c) -> a+2b mod (b+c)

二者应该相等,因此得出 a+b mod (b+c) = 0 即a = c

​ 利用这个结论,我们可以先判断判断链表是否有环,如果有环,那么先找到相间的节点,然后再用一个新指针从头开始以速度为1和low指针从相交节点同时开始遍历,当两个点相交的节点即为环入口节点。

例题:给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def detectCycle(head):
"""
:type head: ListNode
:rtype: ListNode
"""
low,fast = head,head

while fast and fast.next and fast.next:
low, fast = low.next, fast.next.next
if fast==low:
p = head
while p!=low:
p = p.next
low = low.next
return p
return None

3.变形型题目

​ 有一类题目不会明显的说让解决环的问题,但是使用环来解决,往往会起到意想不到的效果。

例题:编写一个程序,找到两个单链表相交的起始节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def getIntersectionNode(headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
if headA==None or headB==None:
return None

#相判断两个是否相交
pA = headA
pB = headB

while pA.next:
pA = pA.next

while pB.next:
pB = pB.next


if pA!=pB:
return None

#将PA首尾相接
tail = pA
pA.next = headA

fast = headB
low = headB

while True:
fast = fast.next.next
low = low.next
if fast==low:
s = headB
while s!=low:
low = low.next
s = s.next
tail.next = None
return s

这道题利用了和上一道题目完全一样的规律解决