天天看点

leetcode习题集——15. 三数之和题目算法1算法2

题目

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

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

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:

[

[-1, 0, 1],

[-1, -1, 2]

]

算法1

public class P15_3Sum {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> rlist = new ArrayList<>();
        Map<String,String> map = new HashMap<>();
        for(int i=0;i<nums.length-2;i++){
            for(int j=i+1;j<nums.length-1;j++){
                for(int k=j+1;k<nums.length;k++){
                    if(nums[i]+nums[j]+nums[k]==0){
                        int[] array = {nums[i],nums[j],nums[k]};
                        Arrays.sort(array);
                        if(map.get(array[0]+","+array[1])==null||map.get(array[0]+","+array[1]).equals("")){
                            map.put(array[0]+","+array[1],"1");
                            List<Integer> l = new ArrayList<>();
                            l.add(nums[i]);
                            l.add(nums[j]);
                            l.add(nums[k]);
                            rlist.add(l);
                        }else {
                            continue;
                        }

                    }
                }
            }
        }
        return rlist;
    }
}

           

思路:这个是我首先想到的暴力解法,三层循环遍历所有可能的三元组情况,再使用Hashmap去重。(方法超时)

算法2

public class P15_3Sum2 {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> ls = new ArrayList<>();

        for (int i = 0; i < nums.length - 2; i++) {
            if (i == 0 || (i > 0 && nums[i] != nums[i - 1])) {  // 跳过可能重复的答案

                int l = i + 1, r = nums.length - 1, sum = 0 - nums[i];
                while (l < r) {
                    if (nums[l] + nums[r] == sum) {
                        ls.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 (nums[l] + nums[r] < sum) {
                        while (l < r && nums[l] == nums[l + 1]) l++;   // 跳过重复值
                        l++;
                    } else {
                        while (l < r && nums[r] == nums[r - 1]) r--;
                        r--;
                    }
                }
            }
        }
        return ls;
    }
}
           

思路:先对数组排序,再将num1+num2+num3=0转换成num2+num3=0-num1来做。

这里求两数之和用到了左右指针法,其中左指针指向num2,右指针指向num3.

因为数组是有序的,所以要使num2+num3和一定,

  1. 连续相等的情况,只移动其中一边的指针
  2. 其余情况需要向内移动左右指针。