【算法】4Sum 四数之和

文章讨论了4Sum问题,即找到数组中四个数的和为目标值的所有不重复四元组。通过分析,指出暴力求解会导致时间复杂度过高。文章提出了排序后固定两数,使用双指针寻找另外两个数的优化方法,并给出了Java代码实现。同时,还讨论了针对特定情况的加速策略,以减少不必要的计算。
摘要由CSDN通过智能技术生成

4Sum 四数之和

问题描述:

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

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

1 < = n u m s . l e n g t h < = 200 − 1 0 9 < = n u m s [ i ] < = 1 0 9 − 1 0 9 < = t a r g e t < = 1 0 9 1 <= nums.length <= 200\\ -10^9 <= nums[i] <= 10^9\\ -10^9 <= target<= 10^9 1<=nums.length<=200109<=nums[i]<=109109<=target<=109

分析

和之前的3sum问题几乎一样,只不过这里的数字多了一个,同时数据的范围最大只有200

也就是说4层循环的暴力是一定TLE的,时间复杂度 O ( N 4 ) O(N^4) O(N4)

如果借鉴3sum的思路来解决,也是先排序,然后固定ab,然后双指针找cd,整体的时间复杂度可以在 O ( N 3 ) O(N^3) O(N3)

从时间复杂度的角度,已经不会有其他的策略可以优于这个思路。

但是以问题的最大数据规模,这个时间复杂度还是会有TLE的风险。

在最差的情况下,所有数据不重复,而且数据的长度达到最大规模时间复杂度的上限就是 O ( N 3 ) O(N^3) O(N3).

但是对于某些特殊的情况下,还是可以进行加速。

和3sum一样的优化思路,

  • 每次固定的ab,一定不能和上一次的ab相等,否则就会出现重复的计算。
  • 如果连续的 a + b + c + d > t a r g e t a+b+c+d>target a+b+c+d>target,那么当前的ab就不可能找到一组符合条件的组合,可以提前break。
  • 如果 a + b + a [ n − 1 ] + a [ n − 2 ] < t a r g e t a+b+a[n-1]+a[n-2]<target a+b+a[n1]+a[n2]<target,说明当前枚举b可能小了,可以提前枚举下一个b。

代码

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        int n = nums.length;
        List<List<Integer>> ans = new ArrayList();
        for(int i = 0;i<n-3;i++){
            if(i>0&&nums[i]==nums[i-1]) continue;
            long a = (long)nums[i];        
            for(int j = i+1;j<n-2;j++){
                if(j>i+1&&nums[j]==nums[j-1]) continue;
                long b = (long)nums[j];
                long tar = (long)target-a-b;
                int l = j+1,r = n-1;
                while(l<r){
                    long x = (long)nums[l]+(long)nums[r];
                    if(x==tar){
                        List<Integer> list = new ArrayList();
                        list.add((int)a);
                        list.add((int)b);
                        list.add(nums[l]);
                        list.add(nums[r]);
                        ans.add(list);
                        l++;r--;
                        while(l<r&&nums[l]==nums[l-1]) l++;
                        while(l<r&&nums[r]==nums[r+1]) r--; 
                    }
                    else if(x<tar){
                        l++;
                    }
                    else{
                        r--;
                    }
                }
            }
        }
        return ans;
    }
}

时间复杂度 O ( N 3 ) O(N^3) O(N3)

空间复杂度 O ( log ⁡ N ) O(\log N) O(logN)

加速

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        int n = nums.length;
        List<List<Integer>> ans = new ArrayList();
        for(int i = 0;i<n-3;i++){
            if(i>0&&nums[i]==nums[i-1]) continue;
            long a = (long)nums[i];  
            long sum = a;
            sum += nums[i+1];
            sum += nums[i+2];
            sum += nums[i+3];
            if(sum>target) break;
            sum = a;
            sum += nums[n-1];
            sum += nums[n-2];
            sum += nums[n-3];
            if(sum<target) continue; 
            for(int j = i+1;j<n-2;j++){
                if(j>i+1&&nums[j]==nums[j-1]) continue;
                long b = (long)nums[j]; 
                sum = a+b;
                sum += nums[j+1];
                sum += nums[j+2];
                if(sum>target) break;
                sum = a+b;
                sum += nums[n-2];
                sum += nums[n-1];
                if(sum<target) continue;
                long tar = (long)target-a-b;
                int l = j+1,r = n-1;
                while(l<r){
                    long x = (long)nums[l]+(long)nums[r];
                    if(x==tar){
                        List<Integer> list = new ArrayList();
                        list.add((int)a);
                        list.add((int)b);
                        list.add(nums[l]);
                        list.add(nums[r]);
                        ans.add(list);
                        l++;r--;
                        while(l<r&&nums[l]==nums[l-1]) l++;
                        while(l<r&&nums[r]==nums[r+1]) r--; 
                    }
                    else if(x<tar){
                        l++;
                    }
                    else{
                        r--;
                    }
                }
            }
        }
        return ans;
    }
}

时间复杂度 O ( N 3 ) O(N^3) O(N3)

空间复杂度 O ( log ⁡ N ) O(\log N) O(logN)

Tag

Array

Sort

Two Pointer

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Eric.Cui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值