C++代码随想录刷题知识分享-----三数之和(3Sum)全解:双指针 + 去重技巧一网打尽
一、题目描述
给定一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足:
i ≠ j ≠ k
nums[i] + nums[j] + nums[k] == 0
请你返回所有 不重复的三元组。
示例:
输入:nums = [-1, 0, 1, 2, -1, -4]
输出:[[-1, -1, 2], [-1, 0, 1]]
注意:
- 结果中不能有重复三元组;
- 顺序不限。
二、解题思路:排序 + 双指针
这是典型的「三数之和 = 固定一数 + 两数之和」问题,整体思路是:
- 对数组
nums
进行排序; - 枚举第一个数
nums[i]
,将问题转化为:在区间
[i+1, n-1]
中找出两个数,使它们的和为-nums[i]
; - 双指针扫描解决;
- 去重处理。
双指针核心思想公式
假设 nums[i] + nums[left] + nums[right] = sum
,我们目标是让 sum == 0
,即:
sum = nums[i] + nums[left] + nums[right]
令:
target = -nums[i]
我们要找的是:
nums[left] + nums[right] == target
这个就是经典的 Two Sum 模式,可以用双指针解决!
三、代码实现(含详细注释)
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> res;sort(nums.begin(), nums.end()); // 排序是关键步骤int n = nums.size();for (int i = 0; i < n; ++i) {if (nums[i] > 0) break; // 剪枝:第一个数大于 0,后面不可能和为 0if (i > 0 && nums[i] == nums[i - 1]) continue; // 跳过重复的 iint left = i + 1;int right = n - 1;while (left < right) {int sum = nums[i] + nums[left] + nums[right];if (sum < 0) {++left; // 需要更大,右移} else if (sum > 0) {--right; // 需要更小,左移} else {res.push_back({nums[i], nums[left], nums[right]});// 去重:跳过重复的 left 和 rightwhile (left < right && nums[left] == nums[left + 1]) ++left;while (left < right && nums[right] == nums[right - 1]) --right;++left;--right;}}}return res;}
};
四、复杂度分析
项目 | 复杂度 | 说明 |
---|---|---|
时间复杂度 | O(n²) | 外层循环 O(n),内层双指针 O(n) |
空间复杂度 | O(1)(忽略输出) | 使用常量指针操作,无额外数据结构 |
五、必须掌握的小技巧 & 模板技巧
1️⃣ 固定 + 双指针模板
sort(nums.begin(), nums.end());
for (int i = 0; i < n; ++i) {if (i > 0 && nums[i] == nums[i - 1]) continue;int left = i + 1, right = n - 1;while (left < right) {...// 同时处理去重}
}
这是后续 四数之和(4Sum)、三数之和变形 的通用模板。
2️⃣ 去重技巧(关键)
- 对外层 i 去重:
if (i > 0 && nums[i] == nums[i-1]) continue;
- 对双指针内层去重:
while (left < right && nums[left] == nums[left + 1]) ++left;
while (left < right && nums[right] == nums[right - 1]) --right;
确保每组答案只出现一次,避免重复提交。
3️⃣ 剪枝优化
一旦 nums[i] > 0
,则三数之和不可能为 0,可立即跳出循环。
六、拓展面试题 & 衍生思维
问题 | 技巧点 |
---|---|
返回三元组中所有满足 a+b+c==target 的组合 | 改 sum == 0 为 sum == target |
四数之和(LeetCode 18) | 固定两个数 + 双指针 |
三数之和接近 target(LC16) | 同样排序 + 双指针 |
判断是否存在三元组(布尔返回) | 提前 return true 即可 |
七、小结
技巧 | 是否掌握 |
---|---|
排序 + 双指针框架 | ✅ |
去重逻辑(外层 & 内层) | ✅ |
提前剪枝优化 | ✅ |
时间复杂度 O(n²) 分析 | ✅ |
总结
三数之和的核心就是固定一数 + 两数之和 = 目标,配合排序和双指针,掌握这题后,k-sum 家族的题你就开启了通关大门!