There are 2 contrived constraints, with out which any circular array has a loop; although not all are clearly stated in the question. Because the array has a finite number of elements, and you can always follow the links for an infinite number of steps, sooner or later you will come back to a visited place.
The constraints are:
(1) Single element loops don't count.
- [5, 5, 5, 5, 5], or [3, 9, 27] should return false.
(2) You can not change directions while following the links.
- [1, -1] should return false.
(I don't see any natural reason or significance to add those constraints, except that it makes a LeetCode problem.)
To address constraint (1), eliminate any place that immediately loops back to itself (identified by having value 0 or multiple of array length), or any place pointing to such locations transitively.
For constraint (2), filter the array into a forward array and a backward one to be searched separately. For instance, [-2, 1, -1, -2, -2] becomes forward [0, 1, 0, 0, 0] and backward [-2, 0, -1, -2, -2] (or equivalently [3, 0, 4, 3, 3]).
Finally, it's no need to use slow/fast pointers. You know there are always loops. Just check whether it contains more than 1 element. Recursively follow the links and mark places leading to a single element loop as 0. When you see the next index is smaller and the value there is not 0, you found one.
class Solution(object): def circularArrayLoop(self, nums): forward = map(lambda x: x % len(nums) if x > 0 else 0, nums) backward = map(lambda x: x % len(nums) if x < 0 else 0, nums) for i in range(len(nums)): if follow(forward, i): return True if follow(backward, i): return True return False def follow(nums, i): if nums[i] == 0: return False nextIndex = (nums[i] + i) % len(nums) # looped back if nextIndex < i and nums[nextIndex] != 0: return True # else continue forward ans = follow(nums, nextIndex) if ans == False: nums[i] = 0 return ans