leetcode#142 Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Solve it without using extra space.

解释:

给定一个单链表,如果单链表中存在环路,则返回环路起始的节点;如果没有环路,则返回null

理解:

这个题可以借鉴leetcode#141的思路,并接着扩展代码即可。在leetcode#141判断的基础上,如果存在环路,则判断headslow是否相同,若相同,则head所指的节点就是环路起始的节点,若不同,则将head移动到下一个节点,同时让slow在环路中跑一圈,看看head会不会与slow相遇。

我的解法:
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
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if(slow == fast) {
break;
}
}
if(fast == null || fast.next == null) { return null; }
else {
while(head != slow) {
if(head != slow && slow != fast) { slow = slow.next; }
else if(head != slow && slow == fast) {
slow = slow.next;
head = head.next;
}
else { break; }
}
return head;
}
}
}
大神解法:

这道题中蕴含着一个数学关系,即fast走过的路程是slow的两倍。

head距离环路起始节点的路程是A,slow在走过路程A之前是不会与fast相遇的;slow离开环路起始节点B路程时,与走完一圈环路的fast 相遇;环路的总长度是N。

所以:

slow走过的路程是:A+B

fast走过的路程是:2(A+B)

环路总长度是:N = 2(A+B)-(A+B) = A+B

此时,做出一张距离关系图之后就会发现,从当前slowfast相遇的节点开始,再走A路程,就可以到达环路起始节点位置,而从head节点到环路起始位置的路程正好是A。所以,只需要再用一个指针slow2head出发,与slow同步行走同样的路程,必然会在环路起始的节点相遇。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast!=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
if (fast == slow){
ListNode slow2 = head;
while (slow2 != slow){
slow = slow.next;
slow2 = slow2.next;
}
return slow;
}
}
return null;
}
}

总结

两种方法都是在leetcode#141原有的基础上进行扩展,但是我的解法没有发现其中蕴含的简单数学关系,而是采取了暴力解法,实在是不应该。

复杂的问题十有八九都会蕴含一定的数学关系或者数学规律,找出这些关系和规律,解题方法将大幅度优化。