leetcode 15.三数之和

leetcode 15.三数之和

题目描述

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意: 答案中不可以包含重复的三元组。

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

解题思路

该题正确的解法是采用双指针的方法,也可以采用回溯法(时间复杂度太高,会超时)。在双指针的写法后面,再补上回溯法的解题方法,可以锻炼一下回溯法的解题思维。

对于该题,首先选择数组中的一个元素作为第一个数,然后其后面通过双指针去获得其他两个数,采用双层循环的方式。具体细节:给定的数组是无序的,并且里面包含重复的元素,要进行排序处理,为什么要进行排序呢?因为在双指针获取其他两个数的时候,只有数组是有序的,才可以知道两个指针是否移动(这里如果不理解看代码)。为了避免目标数组的重复,需要加一些边界条件的判断(具体看代码)

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        // nums的个数小于3,表示没有符合的条件,直接返回
        if(nums.size() < 3){
            return res;
        }
        // nums数组排序
        sort(nums.begin(), nums.end());
        for(int i=0; i<nums.size(); i++){
            int l = i+1;
            int r = nums.size()-1;
            // 当第一个数字大于零的时候,后面的数字也都大于零,表示后面的数都不符合条件,直接跳出循环
            if(nums[i] > 0){
                break;
            }
            // 避免重复; 这是第一个数字的选择,如果当期的数和前一个数相同,继续下一步操作,筛选出来的数就和前一个数的结果相同,就会产生重复的数组,所以这里就直接continue,进入下一次循环中。
            if(i>0 && nums[i] == nums[i-1]){
                continue;
            }
            while(l<r){
                // 找到符合条件的三个数
                if(nums[i]+nums[l]+nums[r] == 0){
                    vector<int> temp = {nums[i], nums[l], nums[r]};
                    l++;     // 左指针加1
                    // 这里也是为了避免重复,给第二个数的筛选条件条件,原理和第一个数的筛选相似
                    if(nums[l] == nums[l-1]){
                        // 如果l和r两个指针相遇了,依然相等,表示后面没有数字了,就把当前结果添加进去
                        if(l == r){
                            res.push_back(temp);
                        }
                        continue;
                    }
                    res.push_back(temp);
                }
                // 大于零,右指针减1
                else if(nums[i]+nums[l]+nums[r] > 0){
                    r--;
                }
                // 小于零,左指针加1
                else{
                    l++;
                }
            }
        }
        return res;
    }
};

回溯法

使用回溯法,就是让程序去尝试着遍历每一种可能的结果,这里时间复杂度太高,结果超时,可以锻炼一下回溯的思维

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        vector<int> track;
        sort(nums.begin(), nums.end());
        backTrack(res, nums, track, 0);
        return res;
    }
    void backTrack(vector<vector<int>>& res, vector<int> nums, vector<int> track, int index){
        if(track.size() == 3){
            if(track[0] + track[1] + track[2] == 0){
                if(find(res.begin(), res.end(), track) == res.end()){
                    res.push_back(track);
                }
            }
            return;
        }
        for(int i=index; i<nums.size(); i++){
            track.push_back(nums[i]);
            backTrack(res, nums, track, i+1);
            track.pop_back();
        }
    }
};

欢迎大家关注我的个人公众号,同样的也是和该博客账号一样,专注分享技术问题,我们一起学习进步
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值