题目:
Given a linked list, return the node where the cycle begins. If there is no cycle, return null
.
Follow up:
Can you solve it without using extra space?
题目分析:题目要求检查一个链表有没有循环,有的话返回循环开始的那个节点,否则返回null,不能使用额外空间。刚开始想,有可能有多个cycles,那样会很复杂。后来仔细一想,这是一个单链表,最多只会有一个循环。想了很久这个题目,没什么头绪,因为链表可能循环,没有办法确定链表有没有终点。
思路:
不知道怎么的蹦出一个很吊的想法(可能以前在哪里见过吧,呵呵。。。不过能记得就挺叼的了,赞一个,哈哈。。。)这个想法就是,同时让两个节点遍历这个链表,一个快一个慢,如果快的和慢的能够相遇,说明有循环!有了这个想法,想一步到位,让快的和慢的相遇在循环开始的节点。发现这样很难实现。于是,退而求其次,先利用这个方法确定有没有循环,然后再找出循环开始节点在哪里。
- 让两个节点,一快一慢遍历链表
- fast节点,每次移动两步;slow节点,每次移动一步;
- 每当有节点移动,就检查fast和slow有没有相遇,有则说明有循环,推出检查
- 同时还要检查,fast有没有走到null,如果走到null,说明没有循环,return null
- 如果有循环,记相遇点为meetPoint
- 如果有循环,查找循环开始的节点
- slow从head出发,一个个检查是否是循环开始节点
- 对于每一个slow,fast都从meetPoint转一圈,看能不能和slow相遇
- 如果相遇,相遇点即为循环开始点
- 如果不相遇,说明slow所在的点还不是循环开始点,令slow=slow.next,fast再从meetPoint转一圈检查
- 如此反复,直到找到循环开始节点
注意点:
- 注意使用标记 tag:...while(或者for)时,可以使用 break tag 或者 continue tag 指定跳出循环的层次
- 注意 do{...}while(...); 的用法
代码:
/**
* 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) {
if(head == null){
return null;
}
ListNode slow,fast,meetPoint;
slow = fast = head;
outer:
while (true){
for (int i =0; i<2; i++){
fast = fast.next;
if (fast == null){
return null;
}
if (fast == slow){
meetPoint = fast;
break outer;
}
}
slow = slow.next;
if (fast == slow){
meetPoint = fast;
break;
}
}
slow = head;
fast = meetPoint;
while (true){
do{
if (fast == slow){
return slow;
}
fast = fast.next;
}while (fast != meetPoint);
slow = slow.next;
}
}
}