https://leetcode-cn.com/problems/circular-array-loop/
题目意思有点饶,看了几遍才读懂。。
题解看了好久才完全看明白,特别是两个循环,以及为什么要这样做的初始化。
核心还是要理解快慢指针,
解题前:
判断是否有环的题目常见的思路就是快慢指针。
对于如何证明快慢指针:就是快指针在后面,一次走两步,慢指针在前,一次走一步。
问题1:怎么证明快慢指针一定会相遇:数学归纳法
当快指针落后慢指针1步时:显然同时走一步会相遇
当快指针落后慢指针2步时:显然同时走一步时候就变成落户1步的情况
假设当落后N步的时候,同时走N次一定相遇,
当落后N+1步的时候,同时走了N次,就说明只差一步,就到了第一种情况。
问题2:怎么证明只有一圈的情况
假设圈的点数为N个,快指针落后的点数必须要小于N个为n。
根据问题一的结论,就得走n次相遇,所以一圈就行。
解题中:
题目主要是有三个难点:
-
在快慢指针中,如何判断所有都是相同的符号(同+同-)?
只要快慢指针前后脚进入到环中就一定满足,快慢指针对应的数值相乘一定>0,且下一步的快指针的数值乘当前的慢指针>0。这样的循环中才能保证所有的数值是相同的。 -
如何判断环的个数大于1?
到了相交点再走一步,看是否相同。 -
如何实现前后脚达到圈内?
循环数组的每个点,只要有环,就肯定可以访问的该点属于环中,如何快指针在慢指针的前一个。这样根据前面的,就可以知道慢指针跑N-1步就可以相遇,加上起点时候就开始判断,就刚好把所有的判断完成。
class Solution {
int[] nums;
int n;
public boolean circularArrayLoop(int[] nums) {
this.n = nums.length;
this.nums = nums;
// 保证有点出现在环内
for(int i = 0; i < n; ++i){
//实现前后脚达到圈内
int slow = i, fast = next(i);
while(nums[fast] * nums[slow] > 0 && nums[next(fast)] * nums[slow] > 0){
if(fast == slow){
if(slow == next(slow)) break; // 存在长度k为1的同向环
else return true; // 否则满足要求
}
// 指针移动
fast = next(next(fast));
slow = next(slow);
}
}
return false;
}
private int next(int i){
// 注意java下标不能像python有负数,-1需要处理成n-1
return ((i + nums[i]) % n + n) % n;
}
}
网友评论