題目
給定一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。
注意:答案中不可以包含重複的三元組。
示例:
給定數組 nums = [-1, 0, 1, 2, -1, -4],
滿足要求的三元組集合爲:
[
[-1, 0, 1],
[-1, -1, 2]
]
來源:力扣(LeetCode)
思路
首先,對原數組進行排序,遍歷排序後的數組,需要注意不是遍歷到最後一個停止,而是到倒數第三個就可以;
其次,可以做個剪枝優化,即遍歷到正數的時候就 break
,因爲數組現在是有序的,如果第一個要 fix 的數就是正數了,則後面的數字就都是正數,就永遠不會出現和爲0的情況;
然後,還要加上重複就跳過的處理,處理方法是從第二個數開始,如果和前面的數字相等,就跳過,因爲不想把相同的數字fix兩次;
再次,對於遍歷到的數,用0減去這個 fix 的數得到一個 target
,然後只需要在之後找到兩個數之和等於 target
即可;
最後,用兩個指針分別指向 fix 數字之後的數組的首尾兩個數,如果兩個數和正好爲 target
,則將這兩個數和 fix 的數一起存入結果中。然後就是跳過重複數字的步驟,兩個指針都需要檢測重複數字。如果兩數之和小於 target
,則將左邊那個指針i右移一位,使得指向的數字增大一些。同理,如果兩數之和大於 target
,則將右邊那個指針j左移一位,使得指向的數字減小一些。
C++代碼
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums)
{
vector<vector<int>> res;
sort(nums.begin(), nums.end());
if (nums.empty() || nums.back() < 0 || nums.front() > 0)
return {};
for (int k = 0; k < (int)nums.size() - 2; ++k)
{
if (nums[k] > 0)
break;
if (k > 0 && nums[k] == nums[k - 1])
continue;
int target = 0 - nums[k], i = k + 1, j = (int)nums.size() - 1;
while (i < j)
{
if (nums[i] + nums[j] == target)
{
res.push_back({nums[k], nums[i], nums[j]});
while (i < j && nums[i] == nums[i + 1])
++i;
while (j < j && nums[j] == nums[j - 1])
--j;
++i;
--j;
}
else if (nums[i] + nums[j] < target)
{
++i;
}
else
{
--j;
}
}
}
return res;
}
};