三数之和
题目描述
给你一个整数数组 nums,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k,同时还满足 nums[i] + nums[j] + nums[k] == 0。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
- 示例 1:
输入:
nums = [-1,0,1,2,-1,-4]输出:[[-1,-1,2],[-1,0,1]]解释:nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0。nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0。nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0。 不同的三元组是[-1,0,1]和[-1,-1,2]。 注意,输出的顺序和三元组的顺序并不重要。
- 示例 2:
输入:
nums = [0,1,1]输出:[]解释:唯一可能的三元组和不为0。
- 示例 3:
输入:
nums = [0,0,0]输出:[[0,0,0]]解释:唯一可能的三元组和为0。
思路分析
这题最省事的做法还是先排序。排序之后,三数之和可以拆成'固定一个数 + 双指针找另外两个数',这样复杂度能压到 O(n^2),也比较好去重。
我这里固定的是最右边的元素 nums[n],然后在它左边用 left 和 right 做对撞。目标其实就是找两个数,让它们的和等于 -nums[n]。如果当前和太小,就把 left 往右移;太大,就把 right 往左收。找到一组后,顺手跳过重复值,不然结果会多出一堆重复三元组。
还有一点,nums[n] < 0 时可以直接停。数组已经排过序,最右边都小于 0,前面只会更小,不可能再凑出 0 了。这种剪枝不花哨,但很实用。
代码编写
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
int n = nums.size() - 1;
vector<vector<int>> result;
(n >= ) {
(nums[n] < ) {
;
}
left = , right = n - ;
target = -nums[n];
(left < right) {
(nums[left] + nums[right] > target) {
--right;
} (nums[left] + nums[right] < target) {
++left;
} {
result.({nums[n], nums[left], nums[right]});
++left;
(left < right && nums[left] == nums[left - ]) {
++left;
}
--right;
(left < right && nums[right] == nums[right + ]) {
--right;
}
}
}
--n;
(n >= && nums[n] == nums[n + ]) {
--n;
}
}
result;
}
};


