15. 三数之和

15. 三数之和

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

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

示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

算法思路:排序 + 双指针

  1. 特判,对于数组长度 len,如果数组为 null 或者数组长度小于 3,返回 []。
  2. 对数组进行排序。
  3. 遍历排序后数组:
    • 若 nums[i]>0:因为已经排序好,所以后面不可能有三个数加和等于 0,直接返回结果。
    • 对于重复元素:跳过,避免出现重复解
    • 令左指针 b = a + 1,右指针 c = len - 1,当 b < c 时,执行循环:
      • 当 nums[a]+nums[b]+nums[c]==0 执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 b, c 移到下一位置,寻找新的解
      • 若和大于 0,说明 nums[c] 太大,c 左移,即 c–;
      • 若和小于 0,说明 nums[b] 太小,b 右移,即 b++;

参考代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();
        if (nums == null || nums.length < 3) {
            return list;
        }
        // 排序
        Arrays.sort(nums);
        int a = 0, b = 0, c = 0, len = nums.length, res = 0;
        // a 固定外层循环
        for (a = 0; a < len - 2; a++) {
            // 第一个元素
            if (nums[a] > 0) {
                break;
            }
            // 去重
            if (a > 0 && nums[a] == nums[a-1]) {
                continue;
            }
           
            b = a + 1;
            c = len - 1;
            // 最小值比较
            int min = nums[a] + nums[b] + nums[b+1];
            if (min > 0) {
                break;
            }
            // 最大值比较
            int max = nums[c] + nums[c-1] + nums[c-2];
            if (max < 0) {
                break;
            }
             // b、c 双指针夹逼
            while (b < c) {
                int target = nums[a] + nums[b] + nums[c];
                if (target == 0) {
                    list.add(Arrays.asList(nums[a], nums[b], nums[c]));
                    b++;
                    c--;
                    // 去重
                    while (b < c && nums[b] == nums[b-1]) {
                        b++;
                    }
                    while (b < c && nums[c] == nums[c + 1]) {
                        c--;
                    }
                } else if (target > 0){
                    c--;
                } else {
                    b++;
                }
            }
        }
        return list;
    }
}

复杂度分析

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)。数组排序 O ( N l o g N ) O(NlogN) O(NlogN,遍历数组 O ( n ) O(n) O(n),双指针遍历 O ( n ) O(n) O(n),总体 O ( N l o g N ) + O ( n ) ∗ O ( n ) O(NlogN) + O(n) * O(n) O(NlogN)+O(n)O(n),即 O ( n 2 ) O(n^2) O(n2)
  • 空间复杂: O ( 1 ) O(1) O(1)

部分图片来源于网络,版权归原作者,侵删。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值