15. 三数之和 Java

该博客介绍了如何使用双指针算法解决寻找数组中和为0的不重复三元组的问题。首先,通过排序数组,然后使用一个外层循环固定一个元素,再使用两个内层循环(双指针)从两侧向中间遍历,通过调整指针位置避免重复三元组。博客提供了两种实现方式,分别是纯净版和破解版,两者都有效地去除了重复的三元组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给你一个包含 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]
输出:[]

 双指针算法需要数组有序。

先想一想,暴力怎么做?

再看看,有没有单调性。

如果有单调性的话,就用双指针来做。

当 i 确定之后,双指针 j 、k 。

 

 

(i 重复了)

 如何去掉重复的三元组?

枚举 i 的时候,如果当前 nums[i]  = 上一个 nums[i] 的值,就跳过,直到 nums[i] 不等于为止。因为在上一个 nums[i] 的时候,已经找出了nums[i] 对应的所有三元组的情况。 

 

(j 重复了)

i 、j 都要判同。

破解版

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++){
            //枚举 i 时,去重。当前这个 i 与前一个 i 相比
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            //左右指针,j   k
            for (int j = i + 1, k = nums.length - 1; j < k; j++){
                ////枚举 j 时,去重。当前这个 j 与前一个 j 相比
                if (j > i +1 && nums[j] == nums[j - 1]) continue;
                /**
                 * 因为k往 左边走是单调递减的,假设右指针当前位置为 k,用 k-1 去试探一下右指针的下一个位置。
                 * 先保证 左右指针 不重叠,即 j < k-1
                 * 如果 [k-1] 这个数满足 nums[i] + nums[j] + nums[k - 1] >=0,
                 * ->说明 [k] 这个数满足 nums[i] + nums[j] + nums[k] > 0 或者 =0,则右指针需要往左边走,因为:
                 *     ->如果[k] 这个数满足 nums[i] + nums[j] + nums[k] > 0,则 [k] 不符合题意,右指针往左走,减小
                 *     ->如果[k] 这个数满足 nums[i] + nums[j] + nums[k] = 0,则 [k-1] 这个数满足 nums[i] + nums[j] + nums[k - 1] = 0,右指针继续往左走
                 *
                 *  确定好 i、j后,相当于要找出 那个
                 *  不与 j 重叠且离 j 最近的(j < k - 1) 并且满足 nums[i] + nums[j] + nums[k] = 0 的 k 的位置
                 *
                 *  j < k - 1,恒成立
                 *  -> j + 1 < k
                 *  -> j < k ,恒成立
                 */
                while (j < k - 1 && nums[i] + nums[j] + nums[k - 1] >=0) k--;
                if (nums[i] + nums[j] +nums[k] == 0){
                    res.add(Arrays.asList(new Integer[]{nums[i],nums[j],nums[k]}));
                }
            }
        }
        return res;
    }
}

纯净版

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可持续化发展

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值