题目

难度:★★★☆☆

类型:数组

方法:快慢指针

力扣链接请移步本题传送门

更多力扣中等题的解决方案请移步力扣中等题目录

给定一个含有正整数和负整数的环形数组 nums。 如果某个索引中的数 k 为正数,则向前移动 k 个索引。相反,如果是负数 (-k),则向后移动 k 个索引。因为数组是环形的,所以可以假设最后一个元素的下一个元素是第一个元素,而第一个元素的前一个元素是最后一个元素。

确定 nums 中是否存在循环(或周期)。循环必须在相同的索引处开始和结束并且循环长度 > 1。此外,一个循环中的所有运动都必须沿着同一方向进行。换句话说,一个循环中不能同时包括向前的运动和向后的运动。

示例

示例 1:

输入:[2,-1,1,2,2]

输出:true

解释:存在循环,按索引 0 -> 2 -> 3 -> 0 。循环长度为 3 。

示例 2:

输入:[-1,2]

输出:false

解释:按索引 1 -> 1 -> 1 ... 的运动无法构成循环,因为循环的长度为 1 。根据定义,循环的长度必须大于 1 。

示例 3:

输入:[-2,1,-1,-2,-2]

输出:false

解释:按索引 1 -> 2 -> 1 -> ... 的运动无法构成循环,因为按索引 1 -> 2 的运动是向前的运动,而按索引 2 -> 1 的运动是向后的运动。一个循环中的所有运动都必须沿着同一方向进行。

提示:

-1000 ≤ nums[i] ≤ 1000

nums[i] ≠ 0

0 ≤ nums.length ≤ 5000

解答

环形数组的判断,建议使用快慢指针。

选取一个索引为起始位置,定义两个指针,慢指针slow每次走一步,快指针fast每次走两步,遍历过程中,查看能否相遇,如果可以相遇,则原数组可以组成环形数组循环。

这里需要注意的是两个特殊情况的判断,一个是快指针或慢指针遍历过程中所遇到的数字的符号需要一致,另一个是循环的长度必须大于1,这里循环的长度意思是慢指针走多少步可以回到最初的位置。

还有一点需要考虑的是,我们需要判断所有索引作为初始位置,只要有一个索引满足从该索引出发可以形成环形数组循环,直接返回True即可,这里需要注意是遇到的元素是0的情况,为了减少遍历,可以考虑将之前遍历走过的路程剔除出去,不需要再次考虑。

class Solution:

def circularArrayLoop(self, nums: List[int]) -> bool:

n = len(nums)

nxt = lambda x: (x + nums[x]) % n

for i in range(n):

if nums[i] == 0:

continue

slow = i

fast = nxt(i)

# 快慢指针

while nums[slow] * nums[nxt(slow)] > 0 and nums[fast] * nums[nxt(fast)] > 0:

if slow == fast:

if slow == nxt(slow):

break

else:

return True

slow = nxt(slow)

fast = nxt(nxt(fast))

# 访问过的置0

index = i

while nums[index] * nums[nxt(index)] > 0:

nums[index] = 0

index = nxt(index)

return False

有关更多力扣中等题的python解决方案,请移步力扣中等题解析