zoukankan      html  css  js  c++  java
  • [LeetCode] 18. 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: 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]
    ]

    解法1: 

      在 3Sum 的基础上再加一层循环即可,3Sum 时间复杂度为 O(n2),所以这个方法时间复杂度为 O(n3)。

    public class Solution {
        public List<List<Integer>> fourSum(int[] nums, int target) {
            List<List<Integer>> res = new ArrayList<>();
            if (nums == null || nums.length < 4) {
                return res;
            }
            
            Arrays.sort(nums);
            for (int i = 0; i < nums.length - 3; i++) {
                if (i > 0 && nums[i] == nums[i - 1]) {
                    continue;
                }
                
                int sum3 = target - nums[i];  // 后3个数之和需等于sum3
                for (int j = i + 1; j < nums.length - 2; j++) {
                    if (j > i + 1 && nums[j] == nums[j - 1]) {
                        continue;
                    }
                    
                    int sum2 = sum3 - nums[j];  // 后2个数之和需等于sum3
                    int left = j + 1, right = nums.length - 1;
                    
                    while (left < right) {
                        if (nums[left] + nums[right] == sum2) {
                            List<Integer> quad = new ArrayList<>();
                            quad.add(nums[i]);
                            quad.add(nums[j]);
                            quad.add(nums[left]);
                            quad.add(nums[right]);
                            res.add(quad);
                            
                            while (left < right && nums[left++] == nums[left]) {}
                            while (left < right && nums[right--] == nums[right]) {}
                            
                        } else if (nums[left] + nums[right] < sum2) {
                            while (left < right && nums[left++] == nums[left]) {}
                            
                        } else {
                            while (left < right && nums[right--] == nums[right]) {}
                        }
                    }
                }
            }
            return res;
        }
    }

    解法2: 

      先排序 (O(nlogn)),然后遍历整个数组,以每两个数的和作为key将两个数的index存于HashMap中,由于存在和相同的情况,因此HashMap中的每个键对应的是一个List,每个List中保存着多组index对,这一操作时间复杂度为 (O(n2))。

      遍历每个key,计算出需要满足4Sum为target的另外一个2Sum,两个2Sum对应的List分别为listA和listB,遍历其中的每一组index,分别为[a0, a1] 和 [b0, b1]。为避免找到index重复的结果,只寻找满足 a0 < b0, a0 < b1, a1 < b0, a1 < b1 的结果,而因为本身就有 a0 < a1, b0 < b1,所以只需满足 a1 < b0 即可。判断找到的结果是否已存在,不存在再把结果加到res中。这一操作比较复杂,时间复杂度不好算,据说是(O(n2logn)),但LeetCode给出的结果是超时。。。。

    public class Solution {
        public List<List<Integer>> fourSum(int[] nums, int target) {
            List<List<Integer>> res = new ArrayList<>();
            if (nums == null || nums.length < 4) {
                return res;
            }
            
            Arrays.sort(nums);
            
            HashMap<Integer, List<Integer[]>> map = new HashMap<>();
            for (int i = 0; i < nums.length - 1; i++) {
                for (int j = i + 1; j < nums.length; j++) {
                    int sum = nums[i] + nums[j];
                    Integer[] pair = {i, j};
                    
                    if (!map.containsKey(sum)) {
                        map.put(sum, new ArrayList<Integer[]>());
                    }
                    map.get(sum).add(pair);
                }
            }
            
            Set<Integer> keys = map.keySet();
            for (int key : keys) {
                List<Integer[]> listA = map.get(key);
                List<Integer[]> listB = map.get(target - key);
                
                if (listA != null && listB != null) {
                    for (Integer[] pairA : listA) {
                        int a0 = pairA[0], a1 = pairA[1];
                        
                        for (Integer[] pairB : listB) {
                            int b0 = pairB[0], b1 = pairB[1];
                            if (a1 < b0) {  // 因为肯定存在: a0 < a1, b0 < b1
                                List<Integer> list = new ArrayList<>();
                                list.add(nums[a0]);
                                list.add(nums[a1]);
                                list.add(nums[b0]);
                                list.add(nums[b1]);
                                if (!res.contains(list)) res.add(list);
                            }
                        }
                    }
                }
            }
            
            return res;
        }
    }
  • 相关阅读:
    [Keyence Programming Contest 2020 E] Bichromization
    [Gym101821B] LIS vs. LDS
    [Ynoi2010]iepsmCmq【数据结构】
    【集训队作业2018】喂鸽子
    【集训队作业2018】复读机
    【NOI2015】荷马史诗
    【IOI2018】组合动作
    【清华集训2017】榕树之心
    【清华集训2016】Alice和Bob又在玩游戏
    1209F
  • 原文地址:https://www.cnblogs.com/strugglion/p/6412116.html
Copyright © 2011-2022 走看看