三数之和——双指针——好难
目录
题目
[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;
}
};
感觉这个过程还蛮复杂的,可能过一段时间再看会清晰一点。