• kSum问题总结


    [LeetCode]1. Two Sum

    题目(题目已修改,和原题要求不一样)

    Given an array of integers, return indices of the two numbers such that they add up to a specific target.
    
    You may assume that each input would have exactly one solution, and you may not use the same element twice.
    

    测试案例

    Given nums = [2, 7, 11, 15], target = 9,
    
    Because nums[0] + nums[1] = 2 + 7 = 9,
    return [0, 1].
    

    思路一

    1. 先将数组排序。
    2. 从左至右依次遍历每个元素,同时在其右边的子序列中采用二分法查找 target 与当前元素的差值。

    代码如下

    class Solution {
        public int[] twoSum(int[] nums, int target) {
            int n = nums.length, pos;
            int[] res = new int[2];
            Arrays.sort(nums);
            for(int i = 0; i < n - 1; i++){
                if((pos = Arrays.binarySearch(nums, i + 1, n, target - nums[i])) > -1){
                    res[0] = nums[i];
                    res[1] = nums[pos];
                    break;
                }
            }
            return res;
        }
    }
    

    思路二

    1. 先将数组排序
    2. 从左至右依次遍历每个元素,同时在其右边的子序列中采用二分法查找 target 与当前元素的差值。由于元素值依次递增,从而,下次二分查找的范围必定在上次二分查找的范围内。所以,可以保存上次二分查找返回的下标。作为下次二分查找的右边界。

    代码如下

    class Solution {
        public int[] twoSum(int[] nums, int target) {
            int n = nums.length, pos = n;
            int[] res = new int[2];
            Arrays.sort(nums);
            for(int i = 0; i < n - 1; i++){
                if((pos = Arrays.binarySearch(nums, i + 1, pos, target - nums[i])) > -1){
                    res[0] = nums[i];
                    res[1] = nums[pos];
                    break;
                }
                //当pos = i + 1 时,说明后面的元素均不满足
                else if((pos = -(pos + 1)) == i + 1){
                    break;
                }
            }
            return res;
        }
    }
    

    思路三

    1. 先将数组排序。

    2. 定义两个下标,start 和 end,初始时,(start = 0, end = n - 1)

    3. 比较 start 和 end 位置处的元素之和与 target 的大小。

      当 nums[start] + nums[end] == target 时,循环结束,找到结果。

      当 nums[start] + nums[end] < target 时,start++。

      当 nums[start] + nums[end] > target 时,end--。

    代码如下

    class Solution {
        public int[] twoSum(int[] nums, int target) {
            int n = nums.length, temp, start = 0, end = n - 1;
            int[] res = new int[2];
            Arrays.sort(nums);
            while(start < end){
                if((temp = nums[start] + nums[end]) > target){
                    end--;
                }
                else if(temp == target){
                    res[0] = nums[start];
                    res[1] = nums[end];
                    break;
                }
                else{
                    start++;
                }
            }
            return res;
        }
    }
    

    [LeetCode 15] 3Sum

    题目

    //题目被简化掉了返回所有组合的结果,仅返回一组。原题在后面
    Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0?
    

    测试案例

    Given array nums = [-1, 0, 1, 2, -1, -4],
    A solution set is: [-1, 0, 1]
    

    思路

    利用2Sum,先将数组进行排序,然后从左至右依次遍历每个元素,对于每个元素,在其右边的子数组中调用2Sum。

    代码如下

    class Solution {
        public List<Integer> threeSum(int[] nums) {
            int n = nums.length;
            Arrays.sort(nums);
            List<Integer> res = null;
            for(int i = 0; i < n -2; i++){
                if((res = twoSum(nums, i + 1, n - 1, -nums[i])) != null){
                    res.add(nums[i]);
                    break;
                }
            }
            return res;
        }
        List<Integer> twoSum(int[] nums, int start, int end, int target){
            int temp;
            List<Integer> res = null;
            while(start < end){
                if((temp = nums[start] + nums[end]) < target){
                    start++;
                }
                else if(temp > target){
                    end--;
                }
                else{
                    res = new ArrayList<>(3);
                    res.add(nums[start]);
                    res.add(nums[end]);
                    break;
                }
            }
            return res;
        }
    }
    

    原题

    Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
    
    Note:
    The solution set must not contain duplicate triplets.
    

    测试案例

    Given array nums = [-1, 0, 1, 2, -1, -4],
    
    A solution set is:
    [
      [-1, 0, 1],
      [-1, -1, 2]
    ]
    

    思路

    1. 在上面3sum的基础上输出所有结果,同时要去重。
    2. 去重的关键在于从左至右遍历每个元素时,如果与前面的元素相同,则不考虑当前元素。
    3. 同时为了输出所有结果,在2sum中,也需要输出所有满足条件的结果及去重。
    4. 在2sum中输出所有结果的思路是:当找到一对结果时,左右下标同时移动。
    5. 在2sum中去重的思路是:每次下标移动时,如果和前继元素相同,则继续移动。

    这是常用的去重思路。

    代码如下

    class Solution {
        public List<List<Integer>> threeSum(int[] nums) {
            int n = nums.length;
            List<List<Integer>> res = new LinkedList<>(), temp;
            Arrays.sort(nums);
            for(int i = 0; i < n - 2; i++){
                //3sum去重
                if(i == 0 || nums[i] != nums[i - 1]){
                    res.addAll(twoSum(nums, i + 1, n - 1, -nums[i]));
                }
            }
            return res;
        }
        List<List<Integer>> twoSum(int[] nums, int start, int end, int target){
            int temp;
            List<Integer> list;
            List<List<Integer>> res = new LinkedList<>();
            while(start < end){
                if((temp = nums[start] + nums[end]) == target){
                    list = new ArrayList<>(3);
                    list.add(nums[start]);
                    list.add(nums[end]);
                    list.add(-target);
                    res.add(list);
                }
                //2sum去重
                if(temp <= target){
                    while(++start < end && nums[start] == nums[start - 1]);
                }
                //2sum去重
                if(temp >= target){
                    while(--end > start && nums[end] == nums[end + 1]);
                }
            }
            return res;
        }
    }
    

    [LeetCode 18] 4Sum

    题目

    Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums 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.
    

    测试案例

    Given array nums = [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(n^3))

    代码

    class Solution {
        List<List<Integer>> result = new LinkedList<>();
        public List<List<Integer>> fourSum(int[] nums, int target) {
            Arrays.sort(nums);        
            int length = nums.length, pre;
            for(int i = 0;i < length - 3; i++){
                if(i > 0 && nums[i] == nums[i - 1]){
                    continue;
                }
                threeSum(nums,target - nums[i], i + 1, nums[i]);
            }
            return result;
        }    
        public void threeSum(int[] nums, int target, int start, int num1){
            int n = nums.length;        
            for(int i = start; i < n - 2; i++){
                if(i > start && nums[i] == nums[i - 1]){
                    continue;
                }
                twosum(nums, i + 1, target - nums[i], num1, nums[i]);
            }        
        }
        void twosum(int[] nums, int start, int target, int num1, int num2){
            int temp, end = nums.length - 1;
            List<Integer> list;
            while(start < end){
                if((temp = nums[start] + nums[end]) == target){
                    list = new ArrayList<>(4);
                    list.add(num1);
                    list.add(num2);
                    list.add(nums[start]);
                    list.add(nums[end]);
                    result.add(list);
                }
                if(temp >= target){
                    while(--end > start && nums[end] == nums[end + 1]);
                }
                if(temp <= target){
                    while(++start < end && nums[start] == nums[start - 1]);
                }
            }
        }
    }
    

    思路2

    1. 将任意两点的和作为key,value为一个 list ,里面存放和值相同的两点的下标,放入 HashMap 中。时间复杂度为 (O(n^2))
    2. 然后两层循环遍历每一对元素,从 target - 和值 对应的 value 中找出满足要求的结点。在 list 中查找的时间复杂度未知。

    kSum

    题目

    Given an unsorted array, determine if there are K elements that sum up to SUM.
    

    思路1

    延续上面思路,在 2sum 外面加 (k - 2) 层循环,时间复杂度为 (O(n^{k - 1}))

    思路2

    将 ksum 问题看作一个二维背包问题。一个约束为 sum,另一个约束为 k。且要求出同时满足的所有所有情况。

    代码如下

    class Solution{
        int min;
        int n;
        boolean[][][] record;
        LinkedList<Integer> stack = new LinkedList<>();
        List<List<Integer>> res = new LinkedList<>();
        public List<List<Integer>> kSum(int[] nums, int k, int sum){
            n = nums.length;
            Arrays.sort(nums);
            min = nums[0];
            sum -= min * k;
            //转变为非负数
            int index = 0;
            while(index < n && (nums[index] - min <= sum)){
                nums[index++] -= min;
            }
            n = index;
            record = new boolean[n + 1][k + 1][sum + 1];
            record[0][0][0] = true;
            for(int i = 1; i <= n; i++){
                for(int j = 0; j <= k; j++){
                    for(int p = 0; p <= sum; p++){
                        record[i][j][p] = record[i - 1][j][p];
                        if(!(record[i][j][p]) && j > 0 && p >= nums[i - 1]){
                            record[i][j][p] = record[i - 1][j - 1][p - nums[i - 1]];
                        }
                    }
                }
            }
            rebuild(nums, n, k, sum);
            return res;
        }
        void rebuild(int[] nums, int index, int k, int sum){
            if(k <= 0){
                res.add(new LinkedList<>(stack));
                return;
            }
            if(record[index - 1][k][sum]){
                rebuild(nums, index - 1, k, sum);
            }
            //选择当前结点,需要进行过滤
            if(sum >= nums[index - 1] && record[index - 1][k - 1][sum - nums[index - 1]]){
                stack.push(nums[index - 1] + min);
                rebuild(nums, index - 1, k - 1, sum - nums[index - 1]);
                stack.pop();
            }
        }
    }
    
  • 相关阅读:
    Hadoop集群(三) Hbase搭建
    Hadoop集群(二) HDFS搭建
    Hadoop集群(一) Zookeeper搭建
    Redis Cluster 添加/删除 完整折腾步骤
    Redis Cluster在线迁移
    Hadoop分布式HA的安装部署
    Describe the difference between repeater, bridge and router.
    what is the “handover” and "soft handover" in mobile communication system?
    The main roles of LTE eNodeB.
    The architecture of LTE network.
  • 原文地址:https://www.cnblogs.com/echie/p/9585312.html
Copyright © 2020-2023  润新知