题目
思路
第一眼看这道题的时候,我脑海里还是“两数之和”的题解。而且根据力扣的提示,似乎将一个元素固定之后,就可以调用“两数之和”的函数,来完成。
于是遍历整个数组,使得target=-nums[i],这样就可以完美调用“两数之和”。
最后采用set为结果数组去重。
不幸的是超时了。
参考网友的题解思路之后,我决定采用双指针。并将左右指针定为i-1和i+1.
然后从i=1开始遍历到i=size-2.
每遇到三数之和等于0的情况,临时建立一个数组,将三个数塞进去,排序后(方便去重)塞进结果数组。然后l++,r–.
如果三数之和小于0,则l++;否则r–.
然后…超时了。最后一个样例一百多个0,没过。
于是我只好改一下双指针的思路。
从l=i-1,r=i+1,改成l=i+1,r=size-1.
然后特别针对最后一个样例,在三数之和sum=0时,如果如果左指针的值不变,就一直跳;右指针也是。从而避免了在最后一个样例中,一次一次的迭代,算出一大堆[0,0,0]的结果后,又要去重的麻烦。
总的来说,三种代码的时间复杂度其实都是O(n²)。但是关键还是在于针对特殊样例的运行时间。力扣有时候做的特别坑…后来才知道这道题不到30%的提交正确率,大部分都是因为一直超时的缘故…
代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
if(nums.size()==0)return ans;//针对其中一个“[]”样例
sort(nums.begin(),nums.end());//排序,方便遍历
for(int i=0;i<nums.size()-1;i++){
if(nums[i]>0)break;//当大于0时,双指针的值必大于0,必然不存在题解
int l=i+1,r=nums.size()-1;//双指针
while(l<r){
//在界限之内
int sum=nums[i]+nums[l]+nums[r];
if(sum==0){
vector<int> tmp;
tmp.push_back(nums[i]);
tmp.push_back(nums[l]);
tmp.push_back(nums[r]);
sort(tmp.begin(),tmp.end());//排序,方便去重
ans.push_back(tmp);
while (l<r && nums[l] == nums[l+1]) l++; // 针对最后一个样例的去重
while (l<r && nums[r] == nums[r-1]) r--; // 去重
r--;l++;
}
else if(sum>0){
r--;
}
else {
l++;
}
}
}
set<vector<int>> st(ans.begin(),ans.end());
ans.assign(st.begin(),st.end());//很方便的set去重
return ans;
}
};
双指针位于左右两侧的代码(最后一个样例超时)
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
if(nums.size()==0)return ans;
sort(nums.begin(),nums.end());
for(int i=1;i<nums.size()-1;i++){
int l=i-1,r=i+1;//双指针
while(l>=0&&r<=nums.size()-1){
//在界限之内
int sum=nums[i]+nums[l]+nums[r];
if(sum==0){
vector<int> tmp;
tmp.push_back(nums[i]);
tmp.push_back(nums[l]);
tmp.push_back(nums[r]);
sort(tmp.begin(),tmp.end());
ans.push_back(tmp);
r++;l--;
}
else if(sum<0){
r++;
}
else {
l--;
}
}
}
set<vector<int>> st(ans.begin(),ans.end());
ans.assign(st.begin(),st.end());
return ans;
}
};
调用“两数之和”的代码(没通过)
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
for(int i=0;i<nums.size();i++){
int t=-nums[i];
vector<int> tmp=twoSum(nums,t,i);
if(tmp[0]!=-99){//-99是为了筛选出有解的情况
tmp.push_back(nums[i]);//得到的2个元素加上该元素,即为一个解
sort(tmp.begin(),tmp.end());//为去重做准备
ans.push_back(tmp);
}
}
set<vector<int>> st(ans.begin(),ans.end());
ans.assign(st.begin(),st.end());
return ans;
}
vector<int> twoSum(vector<int>& n, int t,int index) {
map<int,int> a;
vector<int> b(2,-99);
int len=n.size();
for(int i=0;i<len;i++){
if(i==index)continue;
if(a.count(t-n[i])>0&&a[t-n[i]]!=i){
//不清楚是不是不允许重复元素
b[0]=n[i];
b[1]=n[a[t-n[i]]];//a[t-n[i]]指的是t-n[i]的下标 a起了反函数的作用
}
a[n[i]]=i;
}
return b;
}//两数之和的代码
};