题目描述
知识点
排序+双指针
结果
实现
码前思考
这道题我没有做出来。。。
- 暴力思考:求
a+b+c = 0
,最直观的方法就是枚举a,b,c,也就是组合数 ,这样的会使时间复杂度达到 ,显然不可取; - 既然不能暴力,那么我们需要将原问题再次进行剖析,要另辟蹊径(转换问题,等价问题是解决暴力的首选思想),所谓
a+b+c = 0
,其实就是a = -b-c
。也就是对a
,我们要去寻找-b-c
即可。 - 但是,如果我们直接去找,那么这样的时间复杂度仍然是
(枚举
a
的 乘上枚举-b-c
的 ),但是如果我们对原数组nums
进行排序,然后使用 双指针 ,那么枚举-b-c
的时间复杂度就变成了 ,这样总体时间复杂度就为 了; - 关于不能有重复解的问题,利用上面的排序,我们就可以解决了,真是一举两得。否则,不用排序也挺难解决的,我没写出来就是卡在没有想到排序。
- 另外一个小技巧就是,当我们排序完之后,如果遍历到
nums[k]
大于0时,我们就可以返回结果了,因为后面的数都不可能满足条件了。
代码实现
//采用O(n^2)+hash的解法
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
//特判一些特殊的情况:数组长度小于3的情况
int size = nums.size();
if(size < 3){
return res;
}
//通过排序来解决重复解的问题
sort(nums.begin(),nums.end());
//使用双指针来解决问题
for(int k=0;k<size;k++){
//用于已经排序,所以当当前数字nums[k]为整数时,肯定可以停止了
if(nums[k] > 0){
break;
}
//去除重复解,当nums[k]==nums[k-1]时,说明可以跳过这个k
if(k>0&&nums[k]==nums[k-1]){
continue;
}
//开始双指针操作
int target = 0 - nums[k];
int i= k+1;
int j= size-1;
//只要两个指针没有相遇,代表还在进行筛选
while(i<j){
if(nums[i]+nums[j] == target){
vector<int> tmp;
res.push_back({nums[k],nums[i],nums[j]});
//排除重复解的情况,即nums[i+1]==nums[i],nums[j-1]==nums[j]
while(i<j && nums[i+1] == nums[i]){
i++;
}
while(i<j && nums[j-1] == nums[j]){
j--;
}
i++;
j--;
}else if(nums[i]+nums[j] <target){//意味着i要右移
i++;
}else{ //意味着j要左移
j--;
}
}
}
return res;
}
};
码后反思
- 之前做的时候是遍历
a+b
,然后利用hash找-c
的,结果卡在重复解上,现在想想,只要排个序就能解决这个问题了,以后尝试一下,时间复杂度也是 ,这个想法就没有用到双指针了! - 其实,我不知道双指针是什么,我去学学,查漏补缺呀!
- ⭐⭐⭐⭐⭐如果找某一个特定元素,一个指针就够了。如果是找两个元素满足一定关系(比如求和等于特定值),需要双指针, 当然前提是数组有序。