給你一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出所有滿足條件且不重複的三元組。
注意:答案中不可以包含重複的三元組。
示例:
給定數組 nums = [-1, 0, 1, 2, -1, -4],
滿足要求的三元組集合爲:
[
[-1, 0, 1],
[-1, -1, 2]
]
我們採用分治的思想. 想要找出三個數相加等於0,我們可以對數組依次遍歷, 每一項a[i]我們都認爲它是最終能夠組成0中的一個數字,那麼我們的目標就是找到 剩下的元素(除a[i])兩個相加等於-a[i].
通過上面的思路,我們的問題轉化爲了給定一個數組,找出其中兩個相加等於給定值。找兩個數之間關係的問題一般用雙指針解決即可, 雙指針一般又需要對數組進行排序。 加上我們需要外層遍歷數組,因此總的時間複雜度應該是O(N^2)。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 記住,如果要找兩個數之間的關係,一般都是要用雙指針,這樣只需要一個循環(O(n))
# 而爲了方便知道怎麼移動指針,需要先排序。
# 這道題排序不是瓶頸,所以可以用內置算法調用(O(n*logn))解決
# 排序後,遍歷所有數,對於任何一個數,它以後的那些數字裏面,要找出兩個使得它們的和爲這個數的負數
# 整個算法的複雜度爲O(n^2)
result = []
nums.sort()
n = len(nums)
for i in range(n):
# 已經從小到大排序了,所以如果出現了大於0的數,它後面的數一定都大於0
if nums[i] > 0:
break
if i > 0 and nums[i] == nums[i-1]:
continue
j = i + 1
k = n - 1
# O(n), 移動指針的循環一般用while
while j < k:
if nums[j] + nums[k] == -nums[i]:
result.append([nums[i], nums[j], nums[k]])
while j < k and nums[j+1] == nums[j]:
j += 1
while j < k and nums[k-1] == nums[k]:
k -= 1
j += 1
k -= 1
elif nums[j] + nums[k] < -nums[i]:
# 這個時候說明需要一個更大的數
j += 1
else:
k -= 1
return result