zoukankan      html  css  js  c++  java
  • 四数之和(leetcode18)

    给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

    注意:

    答案中不可以包含重复的四元组。

    示例:

    给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

    满足要求的四元组集合为:
    [
    [-1, 0, 0, 1],
    [-2, -1, 1, 2],
    [-2, 0, 0, 2]
    ]

    分析:

    排序+双指针

    最朴素的方式是:使用四重循环枚举所有的四元组,然后使用哈希表去重,得到不包含重复四元组的答案。

    但是这种时间复杂度为O(n4),空间复杂度也很高。

    因此需要换一种思路。

    为了避免枚举到重复的四元组,需要保证每一重循环枚举到的元素不小于上一重循环枚举到的元素,

    且在同一重循环中不能多次枚举到相同的元素。

    故,可以对数组排序,并在循环中遵从下面两点:

    • 每一种循环枚举到的下标必须大于上一重循环枚举到的下标;
    • 同一重循环中,如果当前元素与上一个元素相同,则跳过当前元素;

    使用上面的方法,可以避免枚举到重复四元组,但是由于仍使用四重循环,时间复杂度仍然是O(n4)。

    因为数组已经排序,可以使用双指针的方法去掉一重循环。

    使用两重循环分别枚举前两个数,然后在两重循环枚举到的数之后使用双指针枚举剩下的两个数。

    假设两重循环枚举到的前两个数分别位于下标 i 和 j,其中 i<j。

    初始时,左右指针分别指向下标 j+1 和下标 n−1。每次计算四个数的和,并进行如下操作:

    如果和等于 target,则将枚举到的四个数加到答案中,然后将左指针右移直到遇到不同的数,将右指针左移直到遇到不同的数;

    如果和小于 target,则将左指针右移一位;

    如果和大于target,则将右指针左移一位。使用双指针枚举剩下的两个数的时间复杂度是 O(n),

    因此总时间复杂度是 O(n^3),低于 O(n^4)

    具体实现时,还可以进行一些剪枝操作

    在确定第一个数之后,如果 nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target,说明此时剩下的三个数无论取什么值,四数之和一定大于 target,因此退出第一重循环;
    在确定第一个数之后,如果 nums[i]+nums[n−3]+nums[n−2]+nums[n−1]<target,说明此时剩下的三个数无论取什么值,四数之和一定小于target,因此第一重循环直接进入下一轮,枚举 nums[i+1];
    在确定前两个数之后,如果nums[i]+nums[j]+nums[j+1]+nums[j+2]>target,说明此时剩下的两个数无论取什么值,四数之和一定大于 target,因此退出第二重循环;
    在确定前两个数之后,如果 nums[i]+nums[j]+nums[n−2]+nums[n−1]<target,说明此时剩下的两个数无论取什么值,四数之和一定小于 target,因此第二重循环直接进入下一轮,枚举 nums[j+1]。

    代码实现

    public class leetcode18 {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    
            Scanner in = new Scanner(System.in);
            String[] numsStr = in.nextLine().split(",");
            int[] nums = new int[numsStr.length];
            for(int i=0;i<numsStr.length;i++){
                nums[i] = Integer.parseInt(numsStr[i]);
            }
            
            int target = Integer.parseInt(in.nextLine());
            List<List<Integer>> result = fourSum(nums,target);
            System.out.println(result);
        }
    
        public static List<List<Integer>> fourSum(int[] nums, int target) {
            List<List<Integer>> quadruplets = new ArrayList<List<Integer>>();
            if(nums==null||nums.length<4){
                return quadruplets;
            }
            Arrays.sort(nums);
            int length = nums.length;
            for(int i=0;i<length-3;i++){
                if(i>0&&nums[i]==nums[i-1]){
                    continue;
                }
                if(nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target){
                    break;
                }
                if(nums[i]+nums[length-3]+nums[length-2]+nums[length-1]<target){
                    continue;
                }
                for(int j=i+1;j<length-2;j++){
                    if(j>i+1&&nums[j]==nums[j-1]){
                        continue;
                    }
                    if(nums[i]+nums[j]+nums[j+1]+nums[j+2]>target){
                        break;
                    }
                    if(nums[i]+nums[j]+nums[length-2]+nums[length-1]<target){
                        continue;
                    }
                    int left=j+1,right=length-1;
                    while(left<right){
                        int sum = nums[i]+nums[j]+nums[left]+nums[right];
                        if(sum==target){
                            quadruplets.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
                            while(left<right&&nums[left]==nums[left+1]){
                                left++;
                            }
                            left++;
                            while(left<right&&nums[right]==nums[right-1]){
                                right--;
                            }
                            right--;
                        }else if(sum<target){
                            left++;
                        }else{
                            right--;
                        }
                    }
                }
            }
            return quadruplets;
        }
    }
  • 相关阅读:
    一些小问题的解决
    JavaScript面向对象的支持
    HTML 5 会为 Flash 和 Silverlight 送终吗?
    Web Forms 2.0 行将被 HTML 5 代替
    XHTML 2: 出师未捷身先死, HTML 5:万千宠爱于一身
    Javascript 技巧大全
    深入了解 HTML 5
    HTML 5 令人期待的 5 项功能
    SQL SERVER 2005中的Schema详解
    VS2008 ,TFS2008破解序列号
  • 原文地址:https://www.cnblogs.com/Vincent-yuan/p/14433331.html
Copyright © 2011-2022 走看看