if ( i > 0and a == nums[i - 1] ): # 跳過重複的「起始值」a,i > 0 是防止出現 nums[0] 跟 nums[-1] 比較,導致比較第一個跟最後一個元素的情況 # a == nums[i - 1] 是避免 不同 index 但 value 一樣 的情況 ex: [-1,-1,...] continue
l, r = i + 1, len(nums) - 1# 左右指針 while l < r: total = a + nums[l] + nums[r] if total > 0: # 因為是 sorted 的,代表 nums[r] 太大了 r -= 1 elif total < 0: l += 1 else: result.append([a, nums[l], nums[r]]) # [-2,-2,0,0,2,2] l += 1 # 跳過重複的 left pointer 值 while l < r and nums[l] == nums[l - 1]: l += 1
return result
TC:O(n^2)
SC:O(n)
為何一開始要
1 2
if a > 0: break
因為 nums 是 sorted 的,所以如果當前的 a 已經大於 0,後面的數字只會更大,就不可能再找到符合條件的組合,例如:
1
nums = [-4, -1, -1, 0, 1, 2]
當 a = -4 或 -1,還可能湊出 0
當 a = 0,還可能有 [0,0,0]
但當 a = 1 的時候,因為後面全是 1, 2, …
最小的總和是 1 + 1 + 2 = 4 > 0。沒必要再檢查,直接結束迴圈
還有為何除了比較下一個值是否與前一個值相同外 a == nums[i - 1],還要比較 i > 0 ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
nums = [0,0,0] nums.sort() result = []
for i, a inenumerate(nums): if nums[i] == nums[i-1]: # ❌ 沒有 i>0 保護 continue
l, r = i+1, len(nums)-1 while l < r: total = a + nums[l] + nums[r] if total == 0: result.append([a, nums[l], nums[r]]) l += 1 r -= 1
print(result)
假設 i 為 0,則 nums[i - 1] 會變成 nums[-1],這樣就會比較當第一個元素與最後一個元素
執行流程
i = 0
判斷:nums[0] == nums[-1] → 0 == 0 → 成立!
所以直接 continue 跳過,連雙指針都沒跑。
第一個合法的 0 被整個跳掉了。
i = 1
判斷:nums[1] == nums[0] → 0 == 0 → 成立,再跳過。
i = 2
判斷:nums[2] == nums[1] → 0 == 0 → 成立,再跳過。
結果變成 result = [],沒找到解,但其實 [0,0,0] 是正解。
Brute Force
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: defthreeSum(self, nums: list[int]) -> list[list[int]]: n = len(nums) results = set() # 用 set 避免重複
for i inrange(n): for j inrange(i + 1, n): for k inrange(j + 1, n): if nums[i] + nums[j] + nums[k] == 0: three_num = tuple(sorted([nums[i], nums[j], nums[k]])) # set 內的元素必須要是能 Hashable的 results.add(three_num)
# set 轉回 list[list] return [list(t) for t in results]
留言版