Is there a loop in the ring array

Time:2022-5-6

Source: leetcode
Link:https://leetcode-cn.com/problems/circular-array-loop

Title Description:

There is a ring array nums without 0. Each nums [i] represents the number of subscripts that the character with subscript i should move forward or backward:
If num [i] is a positive number, move num [i] step forward
If num [i] is negative, move num [i] step backward
Because the array is circular, it can be assumed that moving forward one step from the last element will reach the first element, and moving backward one step from the first element will reach the last element.
The loop in the array consists of a subscript sequence seq with length k:
Following the above movement rules will result in repeated subscript sequence seq [0] – > SEQ [1] – >… – > seq[k – 1] -> seq[0] -> …
All nums [SEQ [J]] should be either all positive or all negative
k > 1
If there is a loop in nums, return true; Otherwise, false is returned.

Example 1:

Input: num = [2, – 1,1,2,2]
Output: true
Explanation: there is a cycle, press the mark 0 – > 2 – > 3 – > 0. The cycle length is 3.

Example 2:

Input: num = [- 1,2]
Output: false
Explanation: press subscript 1 – > 1 – > 1 The motion of cannot form a cycle because the length of the cycle is 1. By definition, the length of the loop must be greater than 1.

Example 3:

Input: num = [- 2,1, – 1, – 2, – 2]
Output: false
Explanation: press subscript 1 – > 2 – > 1 – > The motion of cannot form a loop because num [1] is positive and num [2] is negative.
All nums [SEQ [J]] should be either all positive or all negative.

Topic analysis:
  • Determine whether there is a circular array in the array, so what is a circular array?

There is an array nums [a, B, C, D, e], in which the elements stored at each index position represent the number of bits that the current index should move forward or backward. For example, the next position of array nums index I after moving is equal to nums [i] + I (beyond the array boundary is not considered). If you move n times from a starting point and then return to the origin, it means that the array is a ring array.

For example, the array num [2, 3, 1, 3, 1, – 3] is a ring array. As can be seen from the figure, the index 0 – > 2 – > 3 – > 0 constitutes a loop.

Is there a loop in the ring array

  • Cycle length must be greater than 1
    For example: array nums [- 1,2], although the index 1 – > 1 also forms a loop, it does not meet the requirements and needs to return false

    Is there a loop in the ring array

  • The direction of movement in the cycle should be either all positive or all negative
    For example, if the array num [- 2,1, – 1, – 2, – 2], has a 1 – > 2 – > 1 index and the loop length is greater than 1, you also need to return false, because the loop moves forward and backward at the same time

    Is there a loop in the ring array

Idea 1:
  • Current index I, array num with length len, calculate the next position: next = (Num [i] + I)
    • There are two situations:
  1. Next > = 0, then next = next% len
  2. Next < 0, then next = (next * – 1 = = len)? 0 : (next % len) + len;
  • If the new index position next calculated by one of the above two formulas is equal to I, the cycle length is 1
  • In the process of traversing the array, the first access starts from index 0 and passes through no loop path: 0 – > 1 – > 2 – > 3 – > 5 – > 7 When starting from index 1 again: 1 – > 2 – > 3 – > 5 – > 7 will be accessed repeatedly. The accessed nodes can be maintained through an array. And if a node is accessed repeatedly in the same cycle, it indicates that the array is in a ring.
Code implementation:
class Solution {
    public int[] arr;
    public int[] mark;
    public int len;
    public boolean circularArrayLoop(int[] nums) {
        len = nums.length;
        arr = nums;
        mark = new int[len];
        for (int i = 0; i < len; i++) {
            if (mark[i] != 0) continue;
            if (doubleArr(i)) return true;
        }
        return false;
    }
    public boolean doubleArr(int index) {
        int cur = index;
        boolean flag = arr[cur] > 0;
        boolean plusMinus = flag;
        while (true) {
            int next = arr[cur] + cur;
            if (next >= 0) {
                next = next % len;
            } else {
                next = (next * -1) == len ? 0 : (next % len) + len; 
            }
            if (next == cur) break;
            if (flag && arr[next] < 0) return false;
            if (!flag && arr[next] > 0) return false;
            
            if (mark[next] != 0) {
                if (mark[next] == index + 1) return true;
                if (mark[next] != index + 1) break;
            }
            mark[next] = index + 1;
            cur = next;
        }
        return false;
    }
}
Idea 1:
  • For the problem of finding a ring from an array, it can be abstracted into a linked list, and then solved by using the fast and slow pointer.
    It can be seen from the figure that taking index 0 as the “head node” to expand and abstract into a linked list, the problem becomes to find out whether there are links in the linked list

    Is there a loop in the ring array

Code implementation:
class Solution {
    int[] arr;
    int len;
    public boolean circularArrayLoop(int[] nums) {
        len = nums.length;
        arr = nums;
        for (int i = 0; i < len; i++) {
            if (doubleArr(i, nextIdx(i))) return true;
        }
        return false;
    }
    //Slow: slow pointer, fast: fast pointer
    public boolean doubleArr(int slow, int fast) {
  
        while (true) {
            if (arr[fast] * arr[slow] < 0) return false;  //  Is it in the same direction
            if(arr[nextIdx(fast)] * arr[slow] < 0) return false; //  Is it in the same direction
            If (fast = = slow) {// the fast and slow pointers meet
                if (slow == nextIdx(slow)) return false; //  The cycle length is 1
                return true; 
            }
            fast = nextIdx(nextIdx(fast));
            slow = nextIdx(slow);
        }
    }
    //Calculate the coordinates of the next node
    public int nextIdx(int index) {
        int next = arr[index] + index;
        if (next >= 0) {
            next = next % len;
        } else {
            next = (next * -1) == len ? 0 : (next % len) + len; 
        }
        return next;
    }
}