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;
    }
}
posted @ 2020-04-02 13:24  Tanglement  阅读(142)  评论(0编辑  收藏  举报