You are playing a game involving a circular array of non-zero integers nums. Each nums[i] denotes the number of indices forward/backward you must move if you are located at index i:
nums[i] is positive, move nums[i] steps forward, andnums[i] is negative, move nums[i] steps backward.Since the array is circular, you may assume that moving forward from the last element puts you on the first element, and moving backwards from the first element puts you on the last element.
A cycle in the array consists of a sequence of indices seq of length k where:
seq[0] -> seq[1] -> ... -> seq[k - 1] -> seq[0] -> ...nums[seq[j]] is either all positive or all negative.k > 1Return true if there is a cycle in nums, or false otherwise.
Example 1:
Input: nums = [2,-1,1,2,2] Output: true Explanation: The graph shows how the indices are connected. White nodes are jumping forward, while red is jumping backward. We can see the cycle 0 --> 2 --> 3 --> 0 --> ..., and all of its nodes are white (jumping in the same direction).
Example 2:
Input: nums = [-1,-2,-3,-4,-5,6] Output: false Explanation: The graph shows how the indices are connected. White nodes are jumping forward, while red is jumping backward. The only cycle is of size 1, so we return false.
Example 3:
Input: nums = [1,-1,5,1,4] Output: true Explanation: The graph shows how the indices are connected. White nodes are jumping forward, while red is jumping backward. We can see the cycle 0 --> 1 --> 0 --> ..., and while it is of size > 1, it has a node jumping forward and a node jumping backward, so it is not a cycle. We can see the cycle 3 --> 4 --> 3 --> ..., and all of its nodes are white (jumping in the same direction).
Constraints:
1 <= nums.length <= 5000-1000 <= nums[i] <= 1000nums[i] != 0Follow up: Could you solve it in O(n) time complexity and O(1) extra space complexity?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The problem asks if, starting from some point in a circle, you can follow a path based on given instructions and return to the starting point. The brute force approach is like trying every possible path from every starting point to see if any path forms a cycle.
Here's how the algorithm would work step-by-step:
def circular_array_loop_brute_force(numbers):
array_length = len(numbers)
for start_index in range(array_length):
current_index = start_index
path_length = 0
visited_indices = []
while path_length <= array_length:
next_index = (current_index + numbers[current_index]) % array_length
# Check for zero-length loop
if next_index == current_index:
break
# Rule out mixed direction loops
if numbers[current_index] * numbers[next_index] < 0:
break
# Check if we've returned to the start
if next_index == start_index:
if path_length + 1 >= 1:
return True
else:
break
# Check if index has been visited
if next_index in visited_indices:
break
visited_indices.append(next_index)
current_index = next_index
path_length += 1
return FalseWe want to figure out if a series of hops within a circle will eventually lead us back to where we started. The efficient way to do this is to keep track of where we've been and quickly identify when we're going around in circles, but not the good kind.
Here's how the algorithm would work step-by-step:
def circular_array_loop(nums): array_length = len(nums)
for start_index in range(array_length):
current_index = start_index
path_history = set()
direction = nums[start_index] > 0
while True:
next_index = (current_index + nums[current_index]) % array_length
# If index is out of bounds.
if next_index < 0:
next_index += array_length
# Check for opposite direction.
if (nums[next_index] > 0) != direction:
break
# Cycle detection. Mark the current index as visited.
if next_index in path_history:
# Ensure cycle has length > 1
if next_index == current_index:
break
return True
path_history.add(current_index)
current_index = next_index
# Detect if path has exceeded length
if len(path_history) > array_length:
break
return False| Case | How to Handle |
|---|---|
| Null or empty input array | Return false immediately as no loop can exist. |
| Array of size 1 | Return false since a single element cannot form a loop. |
| All elements are zero | Return false as all movements are stationary, preventing a loop. |
| Array contains only positive numbers that sum to less than the array length | Return false because the loop can never reach all elements to circle back. |
| Array contains only negative numbers that sum to greater than negative the array length | Return false because the loop can never reach all elements to circle back. |
| Array contains a mix of positive and negative numbers that prevent a loop. | The algorithm should still correctly identify that the paths do not result in a loop, and terminate. |
| Integer overflow when calculating the next index. | Use modulo operator (%) to ensure the index remains within the array bounds, preventing overflow. |
| Different direction movements in a single potential loop. | Mark elements visited in the wrong direction as invalid to prevent cycles using opposite signs. |