15. 三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。
请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
📑排序+双指针
对于这道题,最先想到的可能就是三重循环暴力枚举所有可能的三元组,但是这样做肯定是超时且不优雅的。因此要寻求一个更优化的解法,就是排序加双指针。
先对数组进行排序,这样做不仅有助于避免结果中的重复三元组,还为后续应用双指针奠定了基础。一旦数组被排完序,我们可以遍历数组中的每一个元素nums[i]
将其作为潜在的三元组的第一个元素,对于每一个nums[i]
,现在的目标是找到另外两个元素nums[j]
和nums[k]
(k>j>i
),使得nums[j]+nums[k]=-nums[i]
接下来就可以使用双指针来实现这一目标。在每次迭代中,我们设置两个指针:left
指针初始化为i+1
,指向当前元素之后的第一个位置;righ
t指针则指向数组的最后一个元素。通过移动这两个指针,可以尝试找到满足条件的其他两个数。如果left
指针和right
指针所指向的数之和小于-nums[i]
,我们就增加left指针以尝试获得更大的值;反之,如果这个和大于-nums[i]
,我们就减少right
指针以减小总和。当找到一组满足条件的三元组时,我们将它添加到结果集中。为了避免输出重复的答案,在发现一个有效的三元组之后,我们需要跳过所有与当前left或right指针对应的相同元素。
代码实现
vector<vector<int>> threeSum(vector<int>& nums) {sort(nums.begin(),nums.end());int n = nums.size();vector<vector<int>> res;for (int i = 0; i < n - 2; i++) {if (i > 0 && nums[i] == nums[i - 1])continue;int l = i + 1, r = n - 1;while (l < r) {if (nums[i] + nums[l] + nums[r] < 0) {l += 1;} else if (nums[i] + nums[l] + nums[r] > 0) {r -= 1;} else {res.push_back({nums[i], nums[l], nums[r]});// 去重while (l < r && nums[l] == nums[l + 1]) {l += 1;}while (l < r && nums[r] == nums[r - 1]) {r -= 1;}l += 1;r -= 1;}}}return res;
}
这里还有可以优化的点
- 如果当前元素与接下来两个最小的元素之和大于0,则直接终止循环
- 如果当前元素与最大的两个元素之和小于0,则跳过此次循环
下面是稍微优化后的代码
vector<vector<int>> threeSum(vector<int>& nums) {sort(nums.begin(), nums.end());int n = nums.size();vector<vector<int>> res;for (int i = 0; i < n - 2; i++) {// 提前终止条件1: 如果当前元素与接下来两个最小的元素之和大于0,则直接终止循环if (nums[i] + nums[i + 1] + nums[i + 2] > 0) break;// 提前终止条件2: 如果当前元素加上最大的两个元素之和仍小于0,则跳过此次迭代if (nums[i] + nums[n - 1] + nums[n - 2] < 0) continue;// 跳过重复项if (i > 0 && nums[i] == nums[i - 1]) continue;int l = i + 1, r = n - 1;while (l < r) {if (nums[i] + nums[l] + nums[r] < 0) {l += 1;} else if (nums[i] + nums[l] + nums[r] > 0) {r -= 1;} else {res.push_back({nums[i], nums[l], nums[r]});// 去重while (l < r && nums[l] == nums[l + 1]) l += 1;while (l < r && nums[r] == nums[r - 1]) r -= 1;l += 1;r -= 1;}}}return res;
}