算法力扣刷题记录 二十【18题. 四数之和】

前言

哈希篇,继续。
记录 二十【18题. 四数之和】


一、题目阅读

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。

示例 1:

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

示例 2:

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

提示:

1 <= nums.length <= 200
-10^9 <= nums[i] <= 10^9
-10^9 <= target <= 10^9

二、尝试实现

学过“三数之和”,同法炮制可以求解4数之和。但是同样有问题需要注意,先上代码,再说细节点:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());//排序
        vector<vector<int>> result;

        if((nums[nums.size()-1] < 0 && target >= 0) || (nums[0] > 0 && target <= 0)){
            return result;
        }


        for(int a = 0;a < nums.size();a++){
            if(a > 0 && nums[a] == nums[a-1]){  //a去重
                continue;
            }

            for(int b = a+1;b < nums.size();b++){
                if((b-1 > a) && nums[b] == nums[b-1]){///b-1>a。
                    continue;
                }

                int c = b+1;
                int d = nums.size()-1;
                while(c < d){
                    if(nums[a] + nums[b] > target - nums[c] - nums[d]){
                        d--;
                    }else if(nums[a] + nums[b] < target- nums[c]- nums[d]){
                        c++;
                    }else{
                        result.push_back({nums[a],nums[b],nums[c],nums[d]});
                        while(c < d && nums[d] == nums[d-1]){
                            d--;
                        }
                        while(c < d && nums[c] == nums[c+1]){
                            c++;
                        }
                        c++;
                        d--;
                    }
                }
            }
        }
        return result;
    }
};

细节及区别:

  • a,b,c,d分别去重;用c、d作为活动区间,所以c,d去重两个while,注意c<d即可;a去重,保证下标不违法,逐步后移。

    • 重点是b去重,第二层循环,b=a+1,从a+1开始,所以去重应该(b-1 > a),否则nums[b]和nums[a]比较,错误。另外因为先b++再去重,所以nums[b]和nums[b-1]比较。
  • 直接返回部分:

     if((nums[nums.size()-1] < 0 && target >= 0) || (nums[0] > 0 && target <= 0)){
                return result;
            }
    
    • target不再是0,nums元素有正有负(注意提示)。所以能够直接返回的条件是:
    • nums全为负,target >=0,肯定空;
    • nums全为正,target <=0,肯定空;
  • 提示:-109 <= nums[i] <= 109,说明可能(nums[a] + nums[b] +nums[c] + nums[d])超出“int”类型范围,导致运行错误。

    • 怎么控制求和不超过int类型最大值?
    • 把nums[c] + nums[d]移到等式的右边,3个109相加超过int,2个109相加可以不超过int范围。

代码随想录学习

学习内容

思路:同思路。

代码实现区别

  • 去重——操作一样。回顾细节部分第一点;

  • 剪枝:有所区别。回顾细节部分第二点;

    • 参考给出的剪枝操作,分别在第一层a所在循环和第二层b所在循环。
    • 第一层循环剪枝:(nums[a] > target && nums[a] > 0 )。解释原因:nums[a]>0,后面的肯定也是大于0(排过序),加正数会越加越大。所以可以break;
    • 第二层循环剪枝:(nums[a] +nums[b]> target && nums[a] +nums[b] >= 0 ),把nums[a] +nums[b]看作一个整体。为什么呢?
      • target>=0时候肯定没有问题;
      • 当target < 0,nums[a] +nums[b] >= 0,那么nums[b] 一定>= 0,保证nums[b]后面都是正数,往后会越加越大,所以可以break;
      • 如果只是nums[b] >= 0,可以吗?可以。因为nums[b]往后都是正数,加正数会越加越大。在nums[a] +nums[b]> target的基础上。
      • 所以第一个条件得是nums[a] +nums[b]> target 。
  • 超出范围怎么处理?回顾细节部分第三点;

    • 直接转换成long类型。

总结

和“三数之和”思路一致,但同样有细节需要主要:3点。

(欢迎指正,转载表明出处)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值