leetcode 18.四数之和

leetcode 18.四数之和

题目描述

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:

答案中不可以包含重复的四元组。

示例:

给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

解题思路

对于该题选择暴力查询的方法可以实现结果,但是时间复杂度太高。对于暴力方法的优化,选择用双指针的做法。

四数相加解题步骤

  • 数组的长度是否符合要求
  • 进行数组的排序,这样可以为下面条件的遍历和数字的筛选做好准备
  • 选择第一个数字,并加上筛选条件,避免重复
  • 选择第二个数字,加上筛选条件,避免重复
  • 双子座筛选剩下的两个数字,这里左右指针移动的条件四数之和与目标值相比较,具体参考代码注释
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> res;
        // 判断数组是否符合遍历条件
        if(nums.size() < 4){
            return res;
        }
        // 数组排序
        sort(nums.begin(), nums.end());
        // 最外层的for,用于第一个数的选择
        for(int i=0; i<nums.size(); i++){
            // 避免第一个数字重复的选择
            if(i>0 && nums[i] == nums[i-1]){
                continue;
            }
            // 第二个for,用于第二个数字的选择
            for(int j=i+1; j<nums.size(); j++){
                int l=j+1, r=nums.size()-1; // 在第一、二个数的基础上,定义指针位置
                // 避免数组第二个数字的重复
                if(j>i+1 && nums[j] == nums[j-1]){
                    continue;
                }
                // 双指针筛选
                while(l<r){
                    // 满足条件做进一步的筛选
                    if (nums[i] + nums[j] + nums[l] + nums[r] == target){
                        vector<int> temp={nums[i], nums[j], nums[l], nums[r]};
                        l++;
                        // 避免第三个数字的重复
                        if(nums[l] == nums[l-1]){
                            if(l == r){   // 当两个指针相遇时,依然重复,把当前结果保存,并跳出
                                res.push_back(temp);        
                            }
                            continue;
                        }
                        res.push_back(temp);
                    }
                    else if (nums[i] + nums[j] + nums[l] + nums[r] > target){      
                        r--;        // 排序后,数字太大,右指针减小一
                    }
                    else{
                        l++;       // 排序后,数字太小,左指针加上一
                    }
                }
            }
        }

        return res;
    }
};

下面分享一下回溯算法,如果数组太大,在leetcode提交超时,就当锻炼一下回溯算法解题思路了

回溯算法框架

  • 递归出口
  • 去选择满足目标结果的可能的条件
  • 递归
  • 状态重置
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> res;
        vector<int> track;
        sort(nums.begin(), nums.end());
        backTrack(res, nums, track, target, 0);
        return res;
    }
    void backTrack(vector<vector<int>>& res, vector<int> nums, vector<int> track, int target, int index){
        if(track.size() == 4){
            if(target == 0){
                res.push_back(track);
            }
            return ;
        }
        for(int i=index; i<nums.size(); i++){
        	// 该判断是为了避免数组重复
            if(i>index && nums[i] == nums[i-1]){
                continue;
            }
            track.push_back(nums[i]);
            target -= nums[i];
            if(target<0 && nums[i] >=0){
                return;
            }
            backTrack(res, nums, track, target, i+1);
            target += nums[i];
            track.pop_back();
        }
    }
};

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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值