15. 三数之和

在这里插入图片描述
很好的一道题,难点有2,控制时间复杂度和去重操作。
去重操作可以通过先将数组排序解决,如1,0,-1,1,那么1,0,-1和0,-1,1就是重复了,这个用set去重也不简单,因为这两个数组虽然数字一样但是完全不同。所以我们将其排序为-1,0,1,1,这样1只能在第三个数字取到了,我们只要保证第三个数字不要取重复的就行了,也就是和前一次取到的第三个数字比较,如果相等直接continue。
控制时复可不简单,用双指针的操作,这里看似两个循环,但是最多也就循环n次,因为如果指针3和指针2相等了就不用再走了,因为指针2再往后走也不可能出现正确答案了。
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        //去重通过sort,这样子就可以通过下一个和前一个是否相等来判断是否要跳过这个
        //比如-1,1,1,0
        //取第二个数字的时候可以取第一个1和第二个1,所以在取第二个数字的时候要判断和前一次取的第二个数字是否相等
        //用first和second,third来存储下标,这样可以和前一次取的是否一样
        //准确的说就是双指针,确定1后,2和3就是两个指针,缩小区间的同时要记得去重
        vector<vector<int>> res;
        if(nums.size() < 3) return res;
        sort(nums.begin(),nums.end());
        for(int first = 0; first < nums.size(); ++first){
            if(first>0 && nums[first] == nums[first-1]){
                continue;
            }
            int third = nums.size()-1;
            int target = -nums[first];
            for(int second = first+1; second < nums.size(); ++second){
                if(second > first+1 && nums[second] == nums[second-1]){
                    continue;
                }
                //2已经去重
                while(second < third && nums[second] + nums[third] > target){
                    third--;
                }
                //如果指针相等,随着b还要往后移,就不可能找的到别的解了,所以直接break
                if(second == third) break;
                if(nums[second] + nums[third] == target){
                    res.push_back(vector<int>{nums[first],nums[second],nums[third]});
                }
            }
        }
        return res;
    }
};

二刷,dfs超时了。
三指针,三指针,三指针。重要的三指针说三遍。first和second记得去重!!如果取的不是第一位,就判断是否和前一位相等,相等就直接continue。

class Solution {
public:
    //n是现在组合中有几个元素
    // void dfs(vector<int>& nums, int index, int sum){
    //     if(tmp.size() == 3){
    //         //这样去重肯定超时
    //         if(sum == 0 && find(res.begin(),res.end(),tmp) == res.end()){
    //             res.push_back(tmp);
    //         }
    //         tmp.pop_back();
    //         return;
    //     }
    //     for(int i = index; i < nums.size(); ++i){
    //         tmp.push_back(nums[i]);
    //         dfs(nums,i+1,sum+nums[i]);
    //     }
    //     //将这一层的子结点循环完,再将这一层的结点弹出去
    //     tmp.pop_back();
    // }
    vector<vector<int>> threeSum(vector<int>& nums) {
        //不重复很重要!!!是不重复组合,而不是不重复元素,比如(-1,-1,-1,2),那么-1,-1,2就这么一种情况,-1,2,-1就是相同的情况,在递归的同一层不能选相同的元素
        //不能这么简单,-1,-1,0,1就会有相同情况产生,在第一层选两个-1
        //这种就是妥妥的dfs
        vector<vector<int>> res;
        if(nums.size() < 3) return res;
        sort(nums.begin(),nums.end());
        // dfs(nums,0,0);
        // return res;

        //三个指针,确定第一个指针后,将target改为-nums[first],后面两个加起来等于这个就行了
        for(int first = 0; first < nums.size(); ++first){
            //第一层就不能选重复的
            if(first > 0 && nums[first] == nums[first-1]) continue;
            int target = 0-nums[first];
            
            //要在外层就确定3,不能每次移动2就重新来一个3,3和2是并列关系
            int third = nums.size()-1;
            //然后确定指针二和指针三,指针二从first后一个开始,指针三从最后开始,当指针二和三相等时就退出,为什么?
            //当指针二往后移动时,二和三的和只会越来越大,如果二三了二还要往后移动也不可能找的到
            //如果二和三的和大于target,就将三缩小,反之不管,因为二会随着指针后移
            for(int second = first+1; second < nums.size() ;++second){
                if(second > first+1 && nums[second] == nums[second-1]) continue;
                while(second < third && nums[second] + nums[third] > target){
                    third--;
                }
                if(second == third) break;
                else if(nums[second]+nums[third] == target){
                    res.push_back(vector<int>{nums[first],nums[second],nums[third]});
                }
            }
        }
        return res;
    }
};
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页