给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
经过各种优化之后,还是卡在了第311 / 313个用例,这个用例有3000个数。
//给vector拓展,加上id并排序
template<typename T>
bool cmp(T x,T y)
{
return x<y;
}
template<typename T>
vector<pair<T,int>> sortWithId(vector<T>v)
{
vector<pair<T,int>>ans;
ans.resize(v.size());
for(int i=0;i<v.size();i++)ans[i].first=v[i],ans[i].second=i;
sort(ans.begin(),ans.end(),[](pair<T,int>p1,pair<T,int>p2){return cmp(p1.first,p2.first);});
return ans;
}
//2个vector中寻找和为s的对,返回结果的每一行都是[id1,id2]
template<typename T>
vector<vector<int>> findSum(vector<T>v1,vector<T>v2,T s)
{
vector<vector<int>>ans;
int m=min(int(v1.size()*v2.size()),1234567);
ans.reserve(m);
vector<int>tmp(2);
vector<pair<T,int>>v3=sortWithId(v2);
sort(v2.begin(), v2.end(),cmp<T>);
for(int i=0;i<v1.size();i++)
{
auto it1=lower_bound(v2.begin(), v2.end(), s-v1[i]);
auto it2=upper_bound(v2.begin(), v2.end(), s-v1[i]);
tmp[0]=i;
for(auto j=it1;j<it2;j++)
{
tmp[1]=v3[j-v2.begin()].second;
ans.push_back(tmp);
}
}
return ans;
}
//删除二维vector中,含有重复元素的行
template<typename T>
vector<vector<T>> deleteSame(vector<vector<T>>&v)
{
vector<vector<int>>ans;
ans.reserve(v.size());
for(int i=0;i<v.size();i++)
{
for(int j=0;j<v[i].size();j++)for(int k=j+1;k<v[i].size();k++)if(v[i][j]==v[i][k])goto deleteSameHere;
ans.push_back(v[i]);
deleteSameHere:;
}
return ans;
}
//枚举2个vector的两数之和
template<typename T>
vector<T> everySum(vector<T>&v1,vector<T>&v2)
{
vector<T>ans;
ans.resize(v1.size()*v2.size());
int k=0;
for(int i=0;i<v1.size();i++)for(int j=0;j<v2.size();j++)ans[k++]=v1[i]+v2[j];
return ans;
}
//把id数组转化为对应的数v[id]
template<typename T>
vector<T> fgetNumFromId(vector<T> &v,vector<int>id)
{
vector<T>ans;
ans.resize(id.size());
for(int i=0;i<id.size();i++)ans[i]= (id[i]>=0 && id[i]<v.size()) ? v[id[i]] : -1;
return ans;
}
//二维id数组转化对应的数的二维数组
template<typename T>
vector<vector<T>> fgetNumFromId2(vector<T> &v,vector<vector<int>>&id)
{
vector<vector<T>>ans;
ans.reserve(id.size());
for(int i=0;i<id.size();i++)ans.push_back(fgetNumFromId(v,id[i]));
return ans;
}
//二维数组每一行排序
template<typename T>
vector<vector<T>> sort2(vector<vector<T>>&v)
{
for(int i=0;i<v.size();i++)sort(v[i].begin(),v[i].end());
return v;
}
//判断2个vector是否全等
template<typename T>
bool isSame(vector<T>&v1,vector<T>&v2)
{
if(v1.size()-v2.size())return false;
for(int i=0;i<v1.size();i++)if(v1[i]!=v2[i])return false;
return true;
}
//二维数组去掉重复行
template<typename T>
vector<vector<T>> deleteSameLine(vector<vector<T>>&v)
{
vector<vector<T>>ans;
ans.reserve(v.size());
for(int i=0;i<v.size();i++)
{
for(int j=i+1;j<v.size();j++)if(isSame(v[i],v[j]))goto deleteSameLineHere;
ans.push_back(v[i]);
deleteSameLineHere:;
}
return ans;
}
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
map<int,int>m;
for(int i=0;i<nums.size();i++)m[nums[i]]++;
vector<int>tmp(3);
vector<vector<int>>ans2;
tmp[0]=tmp[1]=tmp[2]=0;
if(m[0]>=3)ans2.push_back(tmp);
sort(nums.begin(),nums.end());
for(int i=2;i<nums.size();i++)if(nums[i]==nums[i-2])nums.erase(nums.begin()+i--);
for(int i=1;i<nums.size();i++)if(nums[i]==nums[i-1])
{
if(m[-nums[i]*2] && nums[i])tmp[0]=tmp[1]=nums[i],tmp[2]=-nums[i]*2,ans2.push_back(tmp);
nums.erase(nums.begin()+i--);
}
vector<int>num2=everySum(nums,nums);
vector<vector<int>>ans=findSum(num2,nums,0);
for(int i=0;i<ans.size();i++)ans[i].push_back(ans[i][0]%nums.size()),ans[i][0]/=nums.size();
ans=deleteSame(ans);
ans=fgetNumFromId2(nums,ans);
ans=sort2(ans);
ans=deleteSameLine(ans);
ans.resize(ans.size()+ans2.size());
copy(ans2.begin(),ans2.end(),ans.end()-ans2.size());
return ans;
}
};
如果不是因为最近沉迷写小模板,其实根本不需要这么做的。
用三指针挪来挪去的方法更快。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
map<int,int>m;
for(int i=0;i<nums.size();i++)m[nums[i]]++;
vector<int>tmp(3);
vector<vector<int>>ans,ans2;
ans.reserve(nums.size()*nums.size());
tmp[0]=tmp[1]=tmp[2]=0;
if(m[0]>=3)ans2.push_back(tmp);
sort(nums.begin(),nums.end());
for(int i=2;i<nums.size();i++)if(nums[i]==nums[i-2])nums.erase(nums.begin()+i--);
for(int i=1;i<nums.size();i++)if(nums[i]==nums[i-1])
{
if(m[-nums[i]*2] && nums[i])tmp[0]=tmp[1]=nums[i],tmp[2]=-nums[i]*2,ans2.push_back(tmp);
nums.erase(nums.begin()+i--);
}
for(int i=0;i<nums.size();i++)
{
for(int j=i+1,k=nums.size()-1;j<k;)
{
if(nums[i]+nums[j]+nums[k]>0)k--;
else if(nums[i]+nums[j]+nums[k]<0)j++;
else
{
tmp[0]=nums[i],tmp[1]=nums[j],tmp[2]=nums[k];
ans.push_back(tmp);
k--,j++;
}
}
}
ans.resize(ans.size()+ans2.size());
copy(ans2.begin(),ans2.end(),ans.end()-ans2.size());
return ans;
}
};