18 四数之和(四指针)

43 篇文章 0 订阅

1. 问题描述:

给定一个包含 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]
]

2. 思路分析:

① 根据题目可以知道我们可以取出数组的任意四个字母,将这四个字母加起来的和判断一下是否与目标值target相等,对于数组中的数字,我们可以取也可以不取,所以我们可以使用递归来求解,存在着两个平行状态,但是后面发现当求出结果之后去重很麻烦,很难判断当前满足条件的四个数字与之前的集合是否存在重复,所以没有采取这种方法

② 在领扣的题解中,发现有一个不错的思路,使用的是四个指针a, b, c, d的做法,分别指向四个元素,首先是要对数组中的元素进行排序,排序的目的是为了之后判断取出的元素是否存在重复,在开始的时候令a指向数组的第一个元素,b = a + 1为a下一个元素,c = b + 1为b下一个元素,d指向的是最末尾的元素,判断nums[a]+nums[b]+nums[c]+nums[d]==target是否成立,假如

nums[a]+nums[b]+nums[c]+nums[d] > target那么d指针往前移动,nums[a]+nums[b]+nums[c]+nums[d]< target了那么c指针往后移动

③ 因为求解的是不重复的组合,所以在循环的时候就应该判断一下是否存在之前使用过这个元素了,因为是从数组中选取四个元素,所以排序之后假如存在着重复那么相邻的元素应该是一样的,所以需要从下一个与之前不重复的元素开始,a,b位置判断去掉重复的如下面划线部分:

④ 对于取出的c,d位置的元素也是在判断四个数字是否满足条件的时候也是如此,需要使用循环来去重,并且判断出满足条件四个数字之和等于target的时候需要c++,d--同时操作这样以a,b为当前位置的四种情况才会被判断完,而且下一次d又是从nums.length - 1的位置开始的,并且c往下移动一位了所以会尝试所有的四种不重复的组合(同时移动是为了在一个范围内进行缩小组合因为下一次是从c的下一个位置,d为数组的最后一个位置开始进行组合和判断)

3. 代码如下:

public class Solution {
    /*采用四个指针来进行操作*/
    static List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> res = new ArrayList<>();
        /*使用四个指针也是选择数组中的数字, 并且需要先进行排序*/
        Arrays.sort(nums);
        for (int a = 0; a <= nums.length - 4; ++a){
            if (a > 0 && nums[a] == nums[a - 1]) continue;//确保选择的数字与之前是不一样的
            for (int b = a + 1; b <= nums.length - 3; ++b){
                if (b > a + 1 && nums[b] == nums[b - 1]) continue;
                /*并且令c = b + 1, d = nums.length - 1这样来进行四个数字不重复性的选择*/
                int c = b + 1, d = nums.length - 1;
                while (c < d){
                    if (nums[a] + nums[b] + nums[c] + nums[d] < target){
                        ++c;
                    }
                    else if (nums[a] + nums[b] + nums[c] + nums[d] > target) {
                        --d;
                    }
                    else {
                        List<Integer> list = new ArrayList<>();
                        list.add(nums[a]); list.add(nums[b]); list.add(nums[c]); list.add(nums[d]);
                        res.add(list);
                        while (c < d && nums[c + 1] == nums[c]) ++c;
                        while (c < d && nums[d - 1] == nums[d]) --d;
                        ++c;
                        --d;
                    }
                }
            }
        }
        return res;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值