力扣OJ 15. 三数之和

给你一个包含 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;
    }
};

猜你喜欢

转载自blog.csdn.net/nameofcsdn/article/details/107191577
今日推荐