【力扣刷题】【1-50】15. 三数之和

15. 三数之和

1.双指针法

双指针法后面还有两道题,建议学会本题后,直接尝试做做:
16. 最接近的三数之和
题解:https://blog.csdn.net/Dariuswuhe/article/details/123476607
18. 四数之和
题解:https://blog.csdn.net/Dariuswuhe/article/details/123481072

  • 如果采取暴力遍历,需要三重循环,时间复杂度为O(n3)

  • 我们这里使用双指针法:虽然有三个数字需要同时遍历,但我们可以利用数组排序后的性质,减小第二和第三个数组的时间复杂度:

    • 首先将数组递增排序;

    • 指针ind1不断从头到尾遍历,如果碰到nums[ind1]==nums[ind1-1]的情况,说明碰到了重复元素,直接跳过;

    • 指针ind2位于ind+1,指针ind3=n-1位于尾部,在每次遍历中,我们只移动ind2和ind3;

    • 因为数组是递增的,如果三数之和>0,说明数字太大,就需要将三数之和减小,ind3–;

      同理,如果数字太小,三数之和需要增大,ind2++;

  • 这样,我们在时间复杂度O(n)之内就完成了ind2和ind3的遍历

  • class Solution {
    public:
        vector<vector<int>> threeSum(vector<int>& nums) {
            vector<vector<int>> result;
            int n=nums.size(),ind1,ind2,ind3;
            sort(nums.begin(),nums.end());
            if(n<3){return result;}
            for(int ind1=0;ind1<n;ind1++){
                if(nums[ind1]>0) return result;
                while(ind1>0&&ind1<n-1&&nums[ind1]==nums[ind1-1]){
                    ind1++;
                }
                ind2=ind1+1;//第二个指针从ind+1开始
                ind3=n-1;//第三个指针从n-1,最后一个元素开始
                while(ind2<ind3){
                    if(nums[ind1]+nums[ind2]+nums[ind3]>0){
                        ind3--;//相加结果太大,第三个指针左移以减少整体和
                    }else if(nums[ind1]+nums[ind2]+nums[ind3]<0){
                        ind2++;//相加结果太小,第二个指针右移以增加整体和
                    }else{
                        vector<int> v{nums[ind1],nums[ind2],nums[ind3]};
                        result.push_back(v);
                        ind2++;ind3--;
                        while(ind2<ind3&&nums[ind2]==nums[ind2-1]){
                            ind2++;
                        }
                        while(ind2<ind3&&nums[ind3]==nums[ind3+1]){
                            ind3--;
                        }
                        //两个指针向中间靠拢,去掉重复的元素
                    }
                }
            }
            return result;
        }
    };
    

2.set去重

  • 本题的答案不能出现重复结果,我们在上面通过相同元素跳过的方式去除了重复结果。

  • 但如果一些复杂情况下不能有效分析出去重方式,可以使用STL中的set容器,达到去重的目的,set会将元素自动进行排序、去重,和map一样,是一种关联式容器,实现原理是红黑树。

    • 插入:set.insert();
    • 使用迭代器遍历 auto it=set.begin();
    • 输出元素时加上*, *it;
  • class Solution {
    public:
        vector<vector<int>> threeSum(vector<int>& nums) {
            vector<vector<int>> result;
            set<vector<int>> set1;
            int n=nums.size(),ind1,ind2,ind3;
            sort(nums.begin(),nums.end());
            if(n<3){return result;}
            for(int ind1=0;ind1<n;ind1++){
                if(nums[ind1]>0) break;
                ind2=ind1+1;//第二个指针从ind+1开始
                ind3=n-1;//第三个指针从n-1,最后一个元素开始
                while(ind2<ind3){
                    if(nums[ind1]+nums[ind2]+nums[ind3]>0){
                        ind3--;//相加结果太大,第三个指针左移以减少整体和
                    }else if(nums[ind1]+nums[ind2]+nums[ind3]<0){
                        ind2++;//相加结果太小,第二个指针右移以增加整体和
                    }else{
                        vector<int> v{nums[ind1],nums[ind2],nums[ind3]};
                        set1.insert(v);
                        // cout<<"s:"<<set1.size()<<endl;
                        ind2++;ind3--;
                    }
                }
            }
            for(auto it=set1.begin();it!=set1.end();it++){
                result.push_back(*it);
            }
            return result;
        }
    };
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值