三数之和——双指针——好难
这篇文章发布已经超过两年,部分工具、版本或观点可能已经变化,请结合最新信息判断。
题目
[15. 三数之和]
难度中等4464收藏分享切换为英文接收动态反馈
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 *a,b,c ,*使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
**注意:**答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
提示:
0 <= nums.length <= 3000-105 <= nums[i] <= 105
题解
参考官方题解
思路可以很快确定,难点在于精确调控指针。所以我调了三个小时的代码才通过…可能我单纯就是菜qwq
首先我们想到用三个循环暴力把这些三元组找出来,然后再对结果去重。(话说c++对二维向量去重我也不会呀qwq)那么有没有不需去重的办法呢?
当然有了,且看如下伪代码:
nums.sort() // 对nums排序,使得三元组(a,b,c)满足a<=b<=c
for first = 0 .. n-1
// 只有和上一次枚举的元素不相同,我们才会进行枚举
if first == 0 or nums[first] != nums[first-1] then
for second = first+1 .. n-1
if second == first+1 or nums[second] != nums[second-1] then
for third = second+1 .. n-1
if third == second+1 or nums[third] != nums[third-1] then
// 判断是否有 a+b+c==0
check(first, second, third)
这样保证了两点:
- 第二重循环枚举到的元素不小于当前第一重循环枚举到的元素,且不与上一个枚举到的元素重复。
- 第三重循环枚举到的元素不小于当前第二重循环枚举到的元素,且不与上一个枚举到的元素重复。
不懂的话可以看看官方题解,再找一个数组,比如[-4,-2,-2,-2,0,1,2,2,2,3,3,4,4,6,6]在纸上画一画。
双指针
假设三元组为(a,b,c)。当a确定时,这里的双指针就是b和c,双指针用到了如下性质:
- 在三重枚举的过程中,当a确定时,b增大,c减小。c不用回溯。
- 我写不下去了…其实我理解的很烂
那直接上我的代码吧:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end()); // 排序
int n = nums.size();
vector<vector<int>> res;
int first,second,third; // 定义三个“指针”
for(first=0;first<n;first++){
if(first==0 || nums[first]!=nums[first-1]){ // 这里有个巧妙的地方,
// 先判断first==0,如果成立,不用继续判断,数组不会越界
third = n-1; // 当first+1时,才回溯third
for(second=first+1;second<n;second++){
if(second==first+1 || nums[second]!=nums[second-1]){
while(second<third && nums[first]+nums[second]+nums[third]>0){
third = third-1;
}
if (second == third) {// 指针不能重合
break;
}
if(nums[first]+nums[second]+nums[third]==0){
res.push_back({nums[first],nums[second],nums[third]});
}
}
}
}
}
return res;
}
};
感觉这个过程还蛮复杂的,可能过一段时间再看会清晰一点。
2025年 2 月 23 日更新
这段代码是双指针标准模板,更好理解
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
res = []
for i in range(len(nums)-2):
if i==0 or nums[i]!=nums[i-1]:
left = i+1
right = len(nums)-1
target = 0-nums[i]
# 双指针
while left < right:
if nums[left] + nums[right] == target:
res.append([nums[i], nums[left], nums[right]])
left += 1
right -= 1
# 跳过重复
while left<right and nums[left]==nums[left-1]:
left += 1
while left<right and nums[right]==nums[right+1]:
right -= 1
else:
# 这里无需跳过重复,因为不满足nums[left] + nums[right] == target的过程不会记录
if nums[left]+nums[right] > target:
right -= 1
else:
left += 1
return res
评论区已延迟加载滑到评论区附近时会自动加载,也可以现在手动打开。



