LeetCode 18. 4Sum(四数之和)

34 篇文章 0 订阅
33 篇文章 0 订阅

原题网址:https://leetcode.com/problems/4sum/

Given an array S of n integers, are there elements abc, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:

  • Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
  • The solution set must not contain duplicate quadruplets.

    For example, given array S = {1 0 -1 0 -2 2}, and target = 0.

    A solution set is:
    (-1,  0, 0, 1)
    (-2, -1, 1, 2)
    (-2,  0, 0, 2)

方法一:应用两数之和的方法将时间复杂度降低一维。

public class Solution {
    private List<int[]> twoSum(int base, int[] nums, int target) {
        int i=0, j=nums.length-1;
        List<int[]> result = new ArrayList<>();
        while (i < j) {
            if (base + nums[i] + nums[j] < target) {
                i ++;
            } else if (base + nums[i] + nums[j] > target) {
                j --;
            } else {
                int[] pair = new int[2];
                pair[0] = nums[i];
                pair[1] = nums[j];
                result.add(pair);
                i ++;
            }
        }
        return result;
    }

    public List<List<Integer>> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        Set<String> founded = new HashSet<>();
        List<List<Integer>> result = new ArrayList<>();
        for(int i = 0; i < nums.length - 3; i ++) {
            while (0 < i && i < nums.length - 3 && nums[i] == nums[i-1]) i++;
            if (i >= nums.length - 3) break;
            for(int j = i + 1; j < nums.length - 2; j ++) {
                int[] twos = new int[nums.length - j - 1];
                for(int k = j + 1; k < nums.length; k ++ ) twos[k-j-1] = nums[k];
                List<int[]> pairs = twoSum(nums[i] + nums[j], twos, target);
                for(int p = 0; p < pairs.size(); p ++) {
                    List<Integer> fours = new ArrayList<>(4);
                    fours.add(nums[i]);
                    fours.add(nums[j]);
                    fours.add(pairs.get(p)[0]);
                    fours.add(pairs.get(p)[1]);
                    String s = fours.toString();
                    if (founded.contains(s)) continue;
                    result.add(fours);
                    founded.add(s);
                }
            }
        }
        return result;
         
    }
}

方法二:与方法一相似,深度优先搜索。

public class Solution {
    private void find(int[] nums, int from, int[] quad, int step, int target, List<List<Integer>> results) {
        if (step == 2) {
            int i=from, j=nums.length-1;
            while (i<j) {
                if (nums[i] + nums[j] < target) {
                    i ++;
                } else if (nums[i] + nums[j] > target) {
                    j --;
                } else if (i>from && nums[i]==nums[i-1]) {
                    i ++;
                } else if (j<nums.length-1 && nums[j]==nums[j+1]) {
                    j --;
                } else {
                    quad[2] = nums[i];
                    quad[3] = nums[j];
                    List<Integer> result = new ArrayList<>(4);
                    for(int k=0; k<4; k++) result.add(quad[k]);
                    results.add(result);
                    i ++; 
                    j --;
                }
            }
            return;
        }
        for(int i=from; i<=nums.length-(4-step); i++) {
            if (i>from && nums[i]==nums[i-1]) continue;
            quad[step] = nums[i];
            find(nums, i+1, quad, step+1, target - nums[i], results);
        }
    }
    public List<List<Integer>> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        List<List<Integer>> results = new ArrayList<>();
        find(nums, 0, new int[4], 0, target, results);
        return results;
    }
}

方法三:采用哈希映射保存一半数字之和。

public class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> results = new ArrayList<>();
        Arrays.sort(nums);
        Map<Integer, List<Pair>> sums = new HashMap<>();
        Set<String> set = new HashSet<>();
        for(int i=1; i<nums.length; i++) {
            for(int j=i+1; j<nums.length; j++) {
                if (j>i+1 && nums[j]==nums[j-1]) continue;
                int sum = nums[i]+nums[j];
                List<Pair> pairs = sums.get(target-sum);
                if (pairs == null) continue;
                for(int p=0; p<pairs.size(); p++) {
                    Pair pair = pairs.get(p);
                    String str = nums[pair.i] + "," + nums[pair.j] + "," + nums[i] + "," + nums[j];
                    if (set.contains(str)) continue;
                    set.add(str);
                    List<Integer> result = new ArrayList<>(4);
                    result.add(nums[pair.i]);
                    result.add(nums[pair.j]);
                    result.add(nums[i]);
                    result.add(nums[j]);
                    results.add(result);
                }
            }
            for(int k=0; k<i; k++) {
                if (k>0 && nums[k]==nums[k-1]) continue;
                int sum = nums[k] + nums[i];
                List<Pair> pairs = sums.get(sum);
                if (pairs == null) {
                    pairs = new ArrayList<>();
                    sums.put(sum, pairs);
                }
                pairs.add(new Pair(k, i));
            }
        }
        return results;
    }
}
class Pair {
    int i, j;
    Pair(int i, int j) {
        this.i = i;
        this.j = j;
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值