Leetcode 457.環形數組循環
1 題目描述(Leetcode題目鏈接)
給定一個含有正整數和負整數的環形數組 nums。 如果某個索引中的數 k 爲正數,則向前移動 k 個索引。相反,如果是負數 (-k),則向後移動 k 個索引。因爲數組是環形的,所以可以假設最後一個元素的下一個元素是第一個元素,而第一個元素的前一個元素是最後一個元素。
確定 nums 中是否存在循環(或週期)。循環必須在相同的索引處開始和結束並且循環長度 > 1。此外,一個循環中的所有運動都必須沿着同一方向進行。換句話說,一個循環中不能同時包括向前的運動和向後的運動。
輸入:[2,-1,1,2,2]
輸出:true
解釋:存在循環,按索引 0 -> 2 -> 3 -> 0 。循環長度爲 3 。
輸入:[-1,2]
輸出:false
解釋:按索引 1 -> 1 -> 1 ... 的運動無法構成循環,因爲循環的長度爲 1 。根據定義,循環的長度必須大於 1 。
輸入:[-2,1,-1,-2,-2]
輸出:false
解釋:按索引 1 -> 2 -> 1 -> ... 的運動無法構成循環,因爲按索引 1 -> 2 的運動是向前的運動,而按索引 2 -> 1 的運動是向後的運動。一個循環中的所有運動都必須沿着同一方向進行。
提示:
- -1000 ≤ nums[i] ≤ 1000
- nums[i] ≠ 0
- 0 ≤ nums.length ≤ 5000
進階:
你能寫出時間時間複雜度爲 O(n) 和額外空間複雜度爲 O(1) 的算法嗎?
2 題解
遞歸實現,判斷是否存在正數/負數組成的環。
class Solution:
def circularArrayLoop(self, nums: List[int]) -> bool:
n = len(nums)
def helper(i):
color[i] = 1
j = (i + nums[i]) % n
if i == j or nums[i]*nums[j] < 0: # 如果是圈或者是遇到正負不相同的數就返回False
return False
if color[j] == 1:
return True
return helper(j)
for i in range(n):
color = [0]*n
if helper(i):
return True
return False
快慢指針找環(快指針走兩步,慢指針走一步,有環就會有重合的時候),將訪問過的地方置零。
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[fast] > 0 and nums[fast] * nums[nxt(fast)] > 0:
if slow == fast:
if slow == nxt(slow):
break
return True
slow = nxt(slow)
fast = nxt(nxt(fast))
# 訪問過的置0
val = nums[i]
while val * nums[i] > 0:
tmp = nxt(i)
nums[i] = 0
i = tmp
return False