双指针—三数之和
1、先看题目要求
给一个数组 nums,找出所有不重复的三元组
[a, b, c] 满足:
- a + b + c = 0
- 三个元素下标不同
- 答案不能重复(比如 [-1,-1,2] 不能出现多次)
2、核心解法:排序 + 双指针(最优解)
为什么这么做?
- 排序:方便去重 + 方便双指针移动
- 固定一个数(外层用for循环固定这个数,因为要遍历数组),然后用双指针(内层用while循环移动双指针,因为循环的条件是left<right)找另外两个数,让三数之和 = 0
- 自动去重:排序后相同数字挨在一起,跳过重复(在找到使得sum=0的三个数后,需要同时移动两个指针,这里需要做去重处理,防止指针指向的数和原来的数相等,因为第一个数是固定的,如果第二个数和原来的第三个数一样,那么第三个数也还是和原来一样,因此需要对移动的两个指针做去重处理)即可
完整代码实现如下:
#include
#include
#include
using namespace std;
vector<vector
vector<vector
sort(nums.begin(), nums.end()); // 1. 先排序!关键!
int n = nums.size();
// 2. 固定第一个数 nums[i]
for (int i = 0; i < n; i++) {
// 去重:如果当前数和前一个一样,直接跳过(避免重复三元组)
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1; // 左指针:i 的下一个
int right = n - 1; // 右指针:数组末尾
// 3. 双指针遍历找另外两个数
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
// 找到一组解
res.push_back({nums[i], nums[left], nums[right]});
// 去重:跳过重复的 left
while (left < right && nums[left] == nums[left + 1]) left++;
// 去重:跳过重复的 right
while (left < right && nums[right] == nums[right - 1]) right--;
// 移动指针继续找
left++;
right--;
}
else if (sum < 0) {
// 和太小 → 左指针右移(变大)
left++;
}
else {
// 和太大 → 右指针左移(变小)
right--;
}
}
}
return res;
}
// 测试
int main() {
vector
auto ans = threeSum(nums);
cout << "所有三数之和为0的不重复三元组:" << endl;
for (auto& v : ans) {
cout << v[0] << " " << v[1] << " " << v[2] << endl;
}
return 0;
}
3、双指针规则
left 从 i+1 开始
right 从末尾开始
计算三数之和 sum
三种情况:
sum = 0
✅ 找到答案!加入结果
✅ 跳过重复的 left 和 right
✅ left++,right--
sum < 0
➡ 和太小了
➡ 左指针右移(让数字变大)
sum > 0
⬅ 和太大了
⬅ 右指针左移(让数字变小)
4、去重(最关键!)
题目要求答案不重复
所以:
如果 nums[i] 和前一个数一样 → 跳过
如果 nums[left] 重复 → 跳过
如果 nums[right] 重复 → 跳过
浙公网安备 33010602011771号