题目描述
题目分析
总共分两步:
- 第一步:将nums[i]转换为i的父亲节点列表,此操作可以使得后续找到的环满足k>1的条件
- 第二步:遍历每个元素,对每个元素深度搜索,直到找到根节点或者环
几点说明:
- 环分为有效环和无效环,环在nums[i]的原始值同号则为有效环
- 为了避免对每个元素深度搜索,可以记录深度搜索的路径,同一路径上所有元素深度搜索的结果都相同,因此无需深度搜索同一路径上其他元素
- 一个元素深度遍历后没找到有效路径,则把整个路径的元素nums[i]都设置为-1,无需再次遍历
需要用得到的数据结构有:
- 栈(双端队列)
- 标记数组(列表),用来标记当前元素曾经是否遍历到,若同一个路径上同一个元素两次被遍历,则存在环(有效环/无效环)
python实现
class Solution(object):
def circularArrayLoop(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
# 备份nums
nums_copy=[] # nums_copy = nums 为引用
for i in range(len(nums)):
nums_copy.append(nums[i])
length = len(nums)
# 第一次遍历,nums[i]表示i的父亲节点
for i in range(length):
parents = nums[i]%length
while parents<0:
# 将所有负数转化为正数
parents+=length
if parents == 0:
# nums[i] = -1 表示自身为根节点
nums[i] = -1
else:
nums[i] = (parents+i)%length
# 第二次遍历,深度搜索
path = deque() # 深度搜索的路径
passed = [0]*length # passed[i] = 1 表示i已经遍历过
for i in range(length):
while nums[i]!=-1:
# 从i开始深度搜索,直到找到根节点或者环(有效环/无效环)
if passed[i] == 1:
# 找到环
tmp = [] # 存放整个环
tmp.append(path.pop())
flag = nums_copy[tmp[-1]] # flag = 0 表示环中异号
while tmp[-1] != i:
index = path.pop()
if nums_copy[index]*flag <= 0:
flag = 0
tmp.append(index)
if flag!=0:
# 存在有效环
return True
# (无效环)不是全正或者全负则跳出深度搜索
while tmp:
path.append(tmp[-1])
tmp = tmp[:-1]
break
# 记录经过的位置
path.append(i)
passed[i] = 1
i = nums[i]
# 以i为起点经过的路径不存在有效环,无需再次访问
while path:
nums[path.pop()] = -1
# 不存在有效环
return False