力扣刷题#7:LeetCode15三数之和
这道题让我第一次意识到:双指针原来有两种——之前学的都是同向的,这次遇到了相向的。
题目
给你一个整数数组,找出所有和为 0 且不重复的三元组。
输入: [-1, 0, 1, 2, -1, -4]
输出: [[-1, -1, 2], [-1, 0, 1]]
一点思路都没有
拿到题的时候脑子是空的。三个数?怎么找?暴力三重循环 O(n³) 肯定不行。哈希表?存什么?怎么去重?
我唯一确定的是:这题肯定可以优化到 O(n²),因为 O(n³) 太蠢了。
有了这个信念,我开始想:能不能把三数之和转化成已知的问题?
关键顿悟:三数之和 = 固定一个 + 两数之和
三数之和就是:
对于数组的每个数 nums[i]:
剩下的事情 = 在 i 后面找两个数,加起来等于 -nums[i]
这样就把"三数之和"变成了"一个固定数 + 两数之和"。
但两数之和怎么找?哈希表可以,但去重很麻烦。而且题目不要求下标,只要求值——有没有更好的方法?
为什么要排序
接下来是最关键的一个问题:排序是为了什么?
起初我不理解——排序不是多此一举吗?但答案很直接:
| 不排序 | 排序后 |
|---|---|
| 不知道数的大小关系 | 数组从小到大排列 |
| 双指针没有方向感 | left++ 和变大,right-- 和变小 |
| 去重很难(相同值散落各处) | 跳过相邻重复,一句话搞定 |
| 不能提前结束 | nums[i] > 0 时直接结束 |
排序的 O(n log n) 相对于 O(n²) 来说几乎可以忽略不计。排序让无序变得有序,让指针有了方向。
双指针的两种模式
之前我刷 26/27/283 的时候学的都是快慢指针:
模式 A:同向而行(快慢指针)
26 题:慢指针 k 写入,快指针 i 扫描
27 题:同上
283 题:同上
但三数之和用的是另一种:
模式 B:相向而行(左右夹逼)
left 指向最小数(左端),right 指向最大数(右端)
三数和 = nums[i] + nums[left] + nums[right]
如果和 < 0 → 需要更大的数 → left++(左指针右移)
如果和 > 0 → 需要更小的数 → right--(右指针左移)
↑ ↑
往同一个目标靠近 往同一个目标靠近
两者都是双指针,但用法完全不同。 一个是一快一慢同向走,一个是两端往中间夹逼。想清楚用哪种,取决于数据是有序的还是需要覆盖的。
我的通过代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
if (nums.size() < 3) return {};
sort(nums.begin(), nums.end());
vector<vector<int>> res;
int len = nums.size();
for (int i = 0; i < len - 2; i++) {
// 跳过重复的固定数
if (i > 0 && nums[i] == nums[i - 1]) continue;
int l = i + 1;
int r = len - 1;
while (l < r) {
int sum = nums[i] + nums[l] + nums[r];
if (sum == 0) {
res.push_back({nums[i], nums[l], nums[r]});
l++;
r--;
// 跳过重复的左右指针
while (l < r && nums[l] == nums[l - 1]) l++;
while (l < r && nums[r] == nums[r + 1]) r--;
} else if (sum > 0) {
r--; // 和太大,右指针左移
} else {
l++; // 和太小,左指针右移
}
}
}
return res;
}
};
学到的东西
1. 把陌生问题转化成熟悉问题
"三数之和"我不会,但"两数之和"我会。三数之和 = 固定一个 + 两数之和。拆解之后,问题就变成了已经会的东西。
2. 双指针有两种
之前以为双指针就是快慢指针,今天才知道还有左右夹逼。以后遇到有序数组的求和问题,优先想相向双指针。
3. 排序是为了给指针方向
排序不总是"多此一举"。当排序能让问题的复杂度降一个数量级时,它就是值得的。
4. 去重要在三个地方
- 外层
for跳过重复的固定数(nums[i] == nums[i-1]) - 找到一组后跳过重复的 left(
nums[l] == nums[l-1]) - 找到一组后跳过重复的 right(
nums[r] == nums[r+1])
少一个,结果里就会多出重复的三元组。
下一步
模式 B 的双指针不只用于三数之和,「盛最多水的容器」「两数之和 II」「四数之和」都是同一类题。掌握了这个模式,后面几道就是套模板了。
写于 2026-06-06。从两数之和到三数之和,中间差的不是代码能力,是想不想得到"排序 + 双指针夹逼"这个组合。
本文档由 AI 辅助生成,作者提供问题和思路,综合获得以上内容。

浙公网安备 33010602011771号