判断单链表有环

双指针

穷举遍历

哈希表缓存

快慢指针

p1, p2指针从头开始扫描链表。指针p1每次走1步,指针p2每次走2步。
如果存在环,则指针p1、p2会相遇;如果不存在环,指针fast遇到NULL退出。

步骤演示:

image

ref: https://blog.csdn.net/mucaoyx/article/details/81395782

原理分析:

Q1: 求入环点。

Q2: 求环的长度。

求环长:
从首次相遇节点继续循环前进,直到两个指针第2次相遇。
此时,统计出来的前进次数就是环长。
image

求入环点:
首次相遇时,
指针p1每次只走一步,走过的距离 D+S1
指针p2每次走两步,比p1多走一圈,做过的距离 D + S1 + S2 + S1
p2的速度是p1的两倍,p2走过的距离也是p1的两倍,
===> 2(D+S1) = D + 2S1 + S2
===> D = S2

只要把其中一个指针放回到头节点位置,另一个指针在首次相遇的节点,两个指针每次向前走一步,
最终归相遇的节点,就是入环节点。
image

1
2
3
4
5
6
7
8
public class Node {
int data;
Node next;

public Node(int data) {
this.data = data;
}
}
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public class TestLinked {

public boolean isCycle(Node head) {
if (head.next == null) {
return false;
}
return getSameNode(head) != null;
}

public Integer getLengthOfCycle(Node head) {
if (!isCycle(head)) {
return 0;
}
Node slowNode = getSameNode(head);
Node first = slowNode.next;
Node second = slowNode.next.next;
int i = 1;
while (first != second) {
i++;
first = first.next;
second = second.next.next;
}
return i;
}

private Node getSameNode(Node node) {
Node fastNode = node;
Node slowNode = node;
while (fastNode != null) {
if (fastNode.next != null) {
fastNode = fastNode.next.next;
} else {
fastNode = null;
}
slowNode = slowNode.next;
if (slowNode == fastNode) {
return slowNode;
}
}
return null;
}

public Node getEntranceOfCycle(Node head) {
Node fastNode = head;
Node slowNode = head;
while (fastNode != null) {
if (fastNode.next != null) {
fastNode = fastNode.next.next;
} else {
fastNode = null;
}
slowNode = slowNode.next;
if (slowNode == fastNode) {
fastNode = head;
while (fastNode != slowNode) {
fastNode = fastNode.next;
slowNode = slowNode.next;
}
return slowNode;
}
}
return null;
}

@Test
public void testIsCycle() {
System.out.println(isCycle(Util.createList()));
}

@Test
public void testGetLengthOfCycle() {
System.out.println(getLengthOfCycle(Util.createList()));
}

@Test
public void testGetEntranceOfCycle() {
System.out.println(getEntranceOfCycle(Util.createList()).data);
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Util {

public static Node createList() {
Node node1 = new Node(5);
Node node2 = new Node(3);
Node node3 = new Node(7);
Node node4 = new Node(2);
Node node5 = new Node(6);
Node node6 = new Node(8);
Node node7 = new Node(1);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node6;
node6.next = node7;
node7.next = node4;
return node1;
}
}

参考文章

评论