算法:15. 三数之和

「这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战

题目描述

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

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

  • 示例 1:

输入:nums = [-1,0,1,2,-1,-4]

输出:[[-1,-1,2],[-1,0,1]]

  • 示例 2:

输入:nums = []

输出:[]

  • 示例3

输入:nums = [0]

输出:[]

  • 提示:
  1. 0 <= nums.length <= 3000
  2. -105 <= nums[i] <= 105

题目分析

首先对数组进行排序,使用三个点 i、j 和 k 分别代表要找的三个数。 通过枚举 i 确定第一个数,也就是保证一个点不动,考虑其它两个点的改变,另外两个点 j,k 分别从左边 i + 1 和右边 n - 1 往中间移动,找到满足 nums[i] + nums[j] + nums[k] == 0 的所有组合。 j 和 k 指针的移动逻辑,下面分情况讨论 sum = nums[i] + nums[j] + nums[k] :

  1. 若和大于0,则右指针自减,k 左移,使 sum 变小
  2. 若和小于0,则左指针自加,j 右移,使 sum 变大
  3. 若和等于0,则将三个元素添加至链表中

题目要求答案不能包含重复的三元组,所以在确定第一个数和第二个数的时候,要跳过数值一样的下标。

时间复杂度:O(N^2),其中 N 是数组nums 的长度。

空间复杂度:O(logN)。我们忽略存储答案的空间,额外的排序的空间复杂度为 O(logN)。然而我们修改了输入的数组 nums,在实际情况下不一定允许,因此也可以看成使用了一个额外的数组存储了nums 的副本并进行排序,空间复杂度为 O(N)O(N)。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        if(n<3){
            return ans;
        }
        for(int i = 0;i<n-2;i++){
            if(i>0 && nums[i] == nums[i-1]) continue;
            int j = i+1,k = n-1;
            while(j<k){
                while(j>i+1 && j<n && nums[j] == nums[j-1]) j++;
                if(j>=k){
                    break;
                }
                if(nums[i]+nums[j]+nums[k] < 0){
                    j++;
                }else if(nums[i]+nums[j]+nums[k] > 0){
                    k--;
                }else{
                    ArrayList<Integer> list = new ArrayList<Integer>();
                    list.add(nums[i]);
                    list.add(nums[j]);
                    list.add(nums[k]);
                    ans.add(list);
                    j++;
                }
            }
        }
        return ans;
​
    }
}
复制代码

おすすめ

転載: juejin.im/post/7035638632803205127