力扣15.三数之和

133 阅读3分钟

1. 题目描述

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

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

输入: nums = [-1,0,1,2,-1,-4]
输出: [[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1][-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入: nums = [0,1,1]
输出: []
解释: 唯一可能的三元组和不为 0 。

示例 3:

输入: nums = [0,0,0]
输出: [[0,0,0]]
解释: 唯一可能的三元组和为 0

 

提示:

  • 3 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

2.收获

这道题在代码随想录中是放在哈希中的,所以在第一手看见题目时有些不确定最优解是什么,也完全没想到双指针法。这也是第一道卡了我好几天的题目,有点不太想写。。但是困难还是要攻克的,而且认真看了一遍题解后发现也没有那么难哈,虽然自己想是想不到的哈哈。

首先总结下学到的java知识点吧;

首先是util下的Arrays
java.util.Arrays
https://www.runoob.com/manual/jdk11api/java.base/java/util/Arrays.html
该类包含用于操作数组的各种方法(例如排序和搜索)。 此类还包含一个静态工厂,允许将数组视为列表。
如果指定的数组引用为null,则此类中的方法都抛出`NullPointerException` ,除非另有说明。

这道题用到的方法有:
1.排序
Arrays.sort(nums);
2.Arrays.asList();
static voidsort​(int[] a)将指定的数组按升序排序。
static voidsort​(int[] a, int fromIndex, int toIndex)按升序对数组的指定范围进行排序。
static <T> List<T>asList​(T... a)返回由指定数组支持的固定大小的列表。

这里的难点主要有:

  1. 思路,先排序然后用双指针,
  2. 去重

自己写的代码:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();
        Arrays.sort(nums);
        for(int k = 0; k < nums.length; k++) {
            if(nums[k] > 0) break;
            int i = k + 1;
            int j = nums.length - 1;
            if(k > 0 && nums[k] == nums[k-1]) continue;
            while(i < j) {
                if(nums[k] + nums[i] + nums[j] == 0) {
                    List<Integer> l = new ArrayList<>();
                    l.add(nums[k]);
                    l.add(nums[i]);
                    l.add(nums[j]);
                    list.add(l);
                    while(i < j && nums[i] == nums[++i]);
                    while(i < j && nums[j] == nums[--j]);

                }
                if(nums[k] + nums[i] + nums[j] < 0) {
                    do {
                        i++;
                    }while(i<j && nums[i] == nums[i-1]);
                    continue;
                }
                if(nums[k] + nums[i] + nums[j] > 0) {
                    do {
                        j--;
                    }while(i<j && nums[j] == nums[j+1]);
                    continue;
                }
            }
        }
        return list;
    }
}

题解:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);//排序,nums变成递增数组
        List<List<Integer>> res = new ArrayList<>();
        //k < nums.length - 2是为了保证后面还能存在两个数字
        for(int k = 0; k < nums.length - 2; k++){
            if(nums[k] > 0) break;//若nums[k]大于0,则后面的数字也是大于零(排序后是递增的)
            if(k > 0 && nums[k] == nums[k - 1]) continue;//nums[k]值重复了,去重
            int i = k + 1, j = nums.length - 1;//定义左右指针
            while(i < j){
                int sum = nums[k] + nums[i] + nums[j];
                if(sum < 0){
                    while(i < j && nums[i] == nums[++i]);//左指针前进并去重
                } else if (sum > 0) {
                    while(i < j && nums[j] == nums[--j]);//右指针后退并去重
                } else {
                    res.add(new ArrayList<Integer>(Arrays.asList(nums[k], nums[i], nums[j])));
                    while(i < j && nums[i] == nums[++i]);//左指针前进并去重
                    while(i < j && nums[j] == nums[--j]);//右指针后退并去重
                }
            }
        }
        return res;
    }
}

复杂度分析

  • 时间复杂度O(N2)O(N^2):其中固定指针k循环复杂度 O(N)O(N),双指针 i,j 复杂度 O(N)O(N)

  • 空间复杂度 O(1)O(1):指针使用常数大小的额外空间。