題目鏈結
給你乙個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出所有滿足條件且不重複的三元組。
注意:答案中不可以包含重複的三元組。
示例:
給定陣列 nums =[-
1,0,
1,2,
-1,-
4],滿足要求的三元組集合為:[[
-1,0
,1],
[-1,
-1,2
]]
直接利用三層for迴圈列舉a、b、c,然後觀察a + b + c是否為0:
vectorint>>
threesum
(vector<
int>
& nums));
}}}}
return res;
}
這種做法在允許重複的情況下是沒有問題的,然而題目要求不能有重複。例如對樣例而言,上述**的輸出會多出乙個[0,1,-1],與[-1,0,1]重複。
那麼如何解決重複問題呢?
三數之和問題可以轉化為兩數之和問題。即:
a + b + c =0=
>
b + c =
-a
也就是找到兩數b、c的和為-a。因此,遍歷a可能的n種情況即可將問題轉化為相對簡單兩數之和問題:
//遍歷a
for(
int i =
0; i < n; i++
)}
觀察我們之前重複問題出現的原因。對於輸入:
[-1
,0,1
,2,-
1,-4
]
-1會被遍歷到兩次,因此帶來了重複問題。
一種解決方案是利用資料結構set,這裡我們採取另一種方法——排序。可以得到:
[-4
,-1,
-1,0
,1,2
]
//nums[i]與上乙個數nums[i - 1]相等則直接跳過
//i > 0是為了防止i - 1 < 0 導致陣列越界
if(i >
0&& nums[i]
== nums[i -1]
)
對於b、c的遍歷,可以簡單採用原來三層for迴圈的思路:
//遍歷b
for(
int j = i +
1; j < n; j++
)}
這樣做的時間複雜度是o(n2),有沒有更好的做法?
一種方式是將b、c改為一左一右的雙指標,即:
int k = n -1;
//遍歷b
for(
int j = i +
1; j < n; j++
)}
這樣做可以將遍歷b、c的複雜度降至o(n)。
合理性證明:
令b = nums[j], c = nums[k]。如果當前b + c != -a,要想使b + c = a,有兩種情況:
因此,在b + c < -a時使j右移,反之使k左移即可。這一雙指標的思想與盛水最多的容器十分相似。
class
solution
//target = -a
int target =
-nums[i]
;int k = n -1;
//遍歷b
for(
int j = i +
1; j < n; j++
)//如果b + c > -a,需要將c減小(即指標k左移))
while
(j < k && nums[j]
+ nums[k]
> target)
//左右指標相遇,退出
if(j == k)
if(nums[j]
+ nums[k]
== target));
}}}return res;}}
;
Leetcode15 三數之和(雙指標)
給定乙個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c 使得 a b c 0 找出所有滿足條件且不重複的三元組。注意 答案中不可以包含重複的三元組。例如,給定陣列 nums 1,0,1,2,1,4 滿足要求的三元組集合為 1,0,1 1,1,2 給定乙個包含 n 個...
leetcode15 三數之和 雙指標
給定乙個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c 使得 a b c 0 找出所有滿足條件且不重複的三元組。注意 答案中不可以包含重複的三元組。例如,給定陣列 nums 1,0,1,2,1,4 滿足要求的三元組集合為 1,0 1 1,1,2 本題的關鍵 去重!借...
LeetCode 15 三數之和
15.給定乙個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c 使得 a b c 0 找出所有滿足條件且不重複的三元組。注意 答案中不可以包含重複的三元組 方法一,個人解法正確,但是效率太低,時間複雜度o n 3 時間超時,無法提交至leetcode public s...