这个题目本质上是一个graph 的BFS 题目,虽然光度题目很难看出来。
数组里是的value 表示走几步,负数表示往回走. “If a number k at an index is positive, then move forward k steps. Conversely, if it's negative (-k), move backward k steps.”, 问数组是否存在环。
ps1: 一个元素自循环 不能算circular
ps2: 环的方向一定是一样的, 意味着环里要么全是正数,要么全是负数。
Example 1:
Input: [2,-1,1,2,2] Output: true Explanation: There is a cycle, from index 0 -> 2 -> 3 -> 0. The cycle's length is 3.
Example 2:
Input: [-1,2] Output: false Explanation: The movement from index 1 -> 1 -> 1 ... is not a cycle, because the cycle's length is 1. By definition the cycle's length must be greater than 1.
Example 3:
Input: [-2,1,-1,-2,-2] Output: false Explanation: The movement from index 1 -> 2 -> 1 -> ... is not a cycle, because movement from index 1 -> 2 is a forward movement, but movement from index 2 -> 1 is a backward movement. All movements in a cycle must follow a single direction.
算法: 把数组想象成graph 的定点,从每个顶点出发进行遍历,看是否有cicle,这个遍历的过程本质上就是BFS。 而且从图的每个点都依次进行BFS
如下图所示:
1. 前三个 1,-1 因为 有正有负 所以尽管可以形成环,所以不符合要求。
2. 从1 到-1 时, -1 也被visted了, 记录在vistedAsStart里面, 那么下一次就不用从这个顶点开始了。
3. 如何记录是否有cicle, 记录一个 curVisted, 这个curVisted 不会超过数组的长度N, 所以直接 boolean curVisted[N]就好了,如果 不止一个点(next != cur) 并且符号相同 (nums[next] * nums[cur] >0) 并且遍历过程中发现某个点已经curVisted[next] == ture了,则有环。
public boolean circularArrayLoop(int[] nums) { if(nums == null|| nums.length <2) return false; int n = nums.length; //记录visted 过程中 哪些 已经遍历过了, 下次就不用从这个点开始了 boolean[] vistedAsStart = new boolean[n]; for(int i=0 ; i<n; i++){ if(vistedAsStart[i]) continue; int cur = i; boolean[] curVisted = new boolean[n]; //记录当前遍历状态,最多只会有N 个点 curVisted[cur] = true; while(true){ int next = ((cur+nums[cur])%n+n)%n; vistedAsStart[next] = true; if(next == cur) break; //环里只有一个点 if(nums[cur] * nums[next] <0) break; //方向相反 if(curVisted[next]) { return true; } cur = next; curVisted[cur] = true; } } return false; }