letcode原题链接:142. 环形链表 II - 力扣(LeetCode)
阅读题干,我们可以知道,题目存在两点需求,第一是确定链表中是否存在环,第二需求是,如果存在环形,找出环形起始结点。
针对上述需求,我第一次考虑的思路是暴力解法(两次循环法):
两个指针,第一指针每次固定在一个位置,第二指针向右移动,如果遇到null,返回null,否则循环到底部,然后第二指针移动。
总结:思路错误
第二次考虑的思路是如果存在环状结构,那么如果我让两个指针(fast+slow)以不同的速度进行偏移,只要时间足够,两个指针总能相遇,因此,当相遇时即可判定存在环状结构,需求一解决。
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
int step = 0;
int flash = 0;//标识符,确定是否有环
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
step++;
if(fast == slow){
flash = 1;
break;
}
}
if(flash == 0)
return null;
解决第二需求,确定环形起始结点。从上述判断过程进行逐步分析,可能存在某些规律(自己没发现规律,最终看大佬思路确定解决思路)。将两个游标指针相遇所走的步骤分解如下:
我们发现,2(x+y) = x+y+n*(z+y) , 当n =1 时,x=z , 当 n=2 时 ,x = z +(n-1)(z+y) 。 即一个指针A从head出发走x时,必定和另外一个指针B从相遇点出发的指针在入口处相遇(这个指针B在入口处相遇前比A多走(n-1)圈)
/**
* 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;
int step = 0;
int flash = 0;//标识符,确定是否有环
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
step++;
if(fast == slow){
flash = 1;
break;
}
}
if(flash == 0)
return null;
else {
slow = head;
while(slow != fast){
slow = slow.next;
fast = fast.next;
}
return fast;
}
}
}