zoukankan      html  css  js  c++  java
  • Leet Code 15.三数之和

    给你一个包含n个整数的数组nums,判断nums中是否存在三个元素a,b,c,使得a+b+c=0?请你找出所有满足条件且不可重复的三元组。

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

    暴力解法

    直接三个循环,遍历所有可能性,判断a+b+c=0,是的话记录。如何去除重复的三元组?用set记录三元组。相同三元组即可被去除。

    对于Arrays和泛型需要再学习一遍。

    /**
        * 暴力:超出时间限制
        * @param nums
        * @return
        */
    private List<List<Integer>> directlySolution(int[] nums) {
        if (nums == null || nums.length <= 2) {
            return Collections.emptyList();
        }
        Arrays.sort(nums);
        Set<List<Integer>> result = new LinkedHashSet<>();
        for (int i = 0; i < nums.length; i++) {
            for (int j = i+1; j < nums.length; j++) {
                for (int k = j+1; k < nums.length; k++) {
                    if (nums[i] + nums[j] + nums[k] == 0) {
                        List<Integer> value = Arrays.asList(nums[i], nums[j], nums[k]);
                        result.add(value);
                    }
                }
            }
        }
    
        return new ArrayList<>(result);
    }
    

    Hash解法

    对于每一个a,去寻找是否存在b+c=-a。对于b,如果没有在Map中有-c-a,就将b存入Map。如果找到相应的b和c,将a,b,c放入set集合以去重。

    相比于暴力解法,三重解法变为两重,不如双指针法优化。在于可以更加熟悉Set Map以及泛型的使用。

    import java.util.*;
    import static java.lang.Math.min;
    
    public class leetcode {
        public static void main(String[] args) {
            Scanner scan = new Scanner(System.in);
            int n = scan.nextInt();
            String str = scan.nextLine();
            int[] nums = new int[n];
            for(int i = 0; i < n; i++) {
                nums[i] = scan.nextInt();
            }
            List result = threeSum(nums);
            System.out.println(result);
        }
    
        public static List<List<Integer>> threeSum(int[] nums) {
            //如果nums数组数量不足3个,则返回空
            if(nums.length <= 2) return Collections.emptyList();
    
            Set<List<Integer>> result = new HashSet<>();
            for(int i = 0; i < nums.length-2; i++) {
                Map<Integer,Integer> hashmap = new HashMap<>();
                for(int j = i+1; j < nums.length; j++) {
                    int target = -nums[i]; //b+c=target
                    //以b为基准,判断集合中是否存在target-b
                    Integer c = target - nums[j];
                    if(hashmap.containsKey(c)) {
                        //存在这样的三元组,放入Set
                        List<Integer> value = Arrays.asList(nums[i],nums[j],c);
                        value.sort(Comparator.naturalOrder());
                        result.add(value);
                    }
                    else {
                        //不存在,需要把b存入集合
                        hashmap.put(nums[j],nums[j]);
                    }
                }
            }
            return new ArrayList<>(result);
        }
    }
    

    这样的解法会超出时间限制,如果数组为[0,0,0,...,0]。因此必须用双指针法来优化。

    双指针法

    对数组线排序,排序后固定一个数nums[i],再使用左右指针指向nums[i]后的两端,数字分别为nums[L]和nums[R],计算三者是否满足0

    • 如果nums[i]>0,则三数之和必不为0,结束循环
    • 如果nums[i]==nums[i-1],说明数字重复,会导致结果重复,跳过
    • 当sum0时,nums[L]nums[L+1]会导致结果重复,L++
    • 当sum0时,nums[R]nums[R-1]会导致结果重复,R--
    import java.util.*;
    import static java.lang.Math.min;
    
    public class leetcode {
        public static void main(String[] args) {
            Scanner scan = new Scanner(System.in);
            int n = scan.nextInt();
            String str = scan.nextLine();
            int[] nums = new int[n];
            for(int i = 0; i < n; i++) {
                nums[i] = scan.nextInt();
            }
            List result = threeSum(nums);
            System.out.println(result);
        }
    
        public static List<List<Integer>> threeSum(int[] nums) {
            List<List<Integer>> ans = new ArrayList<>();
            int len = nums.length;
            if(nums == null || len < 3) return ans;
            Arrays.sort(nums);
            for(int i = 0; i<len; i++) {
                if(nums[i] > 0) break;
                if(i>0 && nums[i] == nums[i-1]) continue;
                int L = i+1;
                int R = len-1;
                while (L < R) {
                    int sum = nums[i] + nums[L] + nums[R];
                    if(sum == 0) {
                        ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
                        while (L < R && nums[L] == nums[L+1]) L++;
                        while (L < R && nums[R] == nums[R-1]) R--;
                        L++;
                        R--;
                    }
                    else if (sum < 0) L++;
                    else if (sum > 0) R--;
                }
            }
            return ans;
        }
    }
    
  • 相关阅读:
    P4559 [JSOI2018]列队
    2019.2.14 考试T3 交互题
    2019.2.14 考试T1 FFT
    P3240 [HNOI2015]实验比较 树形DP
    bzoj 3514: Codechef MARCH14 GERALD07加强版 LCT+主席树
    P4172 [WC2006]水管局长 LCT维护最小生成树
    P4177 [CEOI2008]order 最小割
    CF1073G Yet Another LCP Problem SA+权值线段树
    CF1110D Jongmah
    2019.2.10考试T2, 多项式求exp+生成函数
  • 原文地址:https://www.cnblogs.com/chenshaowei/p/12619145.html
Copyright © 2011-2022 走看看