力扣 15.三数之和 题解

题目

在这里插入图片描述

思路

第一眼看这道题的时候,我脑海里还是“两数之和”的题解。而且根据力扣的提示,似乎将一个元素固定之后,就可以调用“两数之和”的函数,来完成。

于是遍历整个数组,使得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;
    }//两数之和的代码
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值