欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

leetcode 15.三数之和

程序员文章站 2022-07-15 11:16:48
...

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();
        }
    }
};

欢迎大家关注我的个人公众号,同样的也是和该博客账号一样,专注分享技术问题,我们一起学习进步
leetcode 15.三数之和