哈希表——8.力扣题目:18. 四数之和

文章描述了一种使用双指针解决寻找数组中四个数之和为目标值的问题,方法是在排序后的数组上进行三层循环,避免使用哈希表,主要通过调整左右指针来优化搜索过程,并在找到解后进行去重处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

解析:(双指针,不使用哈希表)

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

示例 1:

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

大体思路:这道题比上一题三数之和,多了一个数,是四数之和。其实就是在三数之和上再套一层for循环。对数组进行遍历,每次遍历下计算三数之和。同样的道理五数之和就是再加一层for循环。

具体做法,先对数组进行升序排序

第一层for循环,nums[i]是每次for循环的元素,在第一个数确认是num[i]下,找剩下三个数的所有可能的答案。(这里注意如果nums[i]>0并且nums[i]>target,就直接返回res,因为num[i]>0说明是num[i]往后正数,num[i]>target说明四个数而且是正数加起来一定大于target)

第二层for循环,j从num[i]后面一位也就是i+1开始迭代,在第二个数确认是num[j]下,找剩下两个数所有的可能的答案。

上面两个数,都要注意去重。就是去除已经变遍历过的而且值一样的。注意必须是确定这个值已经遍历过了,而且值相同,所以是nums[i]和nums[i-1]比较,nums[j] 和 nums[j-1]比较。nums[i-1]和nums[j-1]肯定是已经遍历过的。

剩下两个数所有的可能的答案,就是使用双指针去找。和三数之和那题一样。

定义left指向j的后一位,定义right指向最后一位

对遍历到的四个数求和:sum = nums[i] + nums[j] + nums[left] + nums[right];

如果sum < target; 说明偏小了,需要调大一点,left后移一位,left++

如果sum > target; 说明偏大了,需要调小一点,right前移一位,right–

如果sum == target;说明找到了一个结果,添加入res。但是要注意去重,因为答案不可以重复,所以这里需要去重,判断left+1位置的值和left位置的值是否相等,相等则left后移一位,并且继续判断(所以使用while),同样对right判断right-1位置的值和right位置的值是否相等,相等则right前移一位并且继续判断。

去重的核心思路:已经将该四元组答案添加进res中后,一直按照上述移动到不重复为止。

同样在去重过程中,需要关注左右指针不可以越界,使用left<right作为每次去重前提条件即可。

注意点:有一个边界条件和三数之和不同

三数之和是和0比较的,三数之和只要第一个数大于0,就可以直接结束程序。因为后面越加越大,肯定>0.

和三数之和不同,四数之和和target比较,仅仅满足num[i] > target还不足以结束程序,因为如果num[i]是负数,num[i]后面的也是负数,负数越加越小。所以还要满足num[i] > 0 ,即num[i]以及num[i]往后的是正数才行

代码:
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > 0 && nums[i] > target) return res;
            if (i >= 1 && nums[i] == nums[i - 1]) continue;
            for (int j = i + 1; j < nums.length; j++) {
                if (j >= i + 2 && nums[j] == nums[j - 1]) continue;
                int left = j + 1, right = nums.length - 1;
                while (left < right) {
                    long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum < target) left++;
                    else if (sum > target) right--;
                    else {
                        res.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        while (left < right && nums[left] == nums[left + 1]) left++;
                        while (left < right && nums[right] == nums[right - 1]) right--;
                        left++;
                        right--;
                    }
                }
            }
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值