LeetCode Hot100(6/100)——15. 三数之和

文章目录

一、题目描述

题目地址:LeetCode - 3Sum

给定一个长度为 n 的整数数组 nums,要求找出所有 唯一的三元组 [nums[i], nums[j], nums[k]],使得:

复制代码
nums[i] + nums[j] + nums[k] == 0

并且:

复制代码
i != j, j != k, i != k

返回所有不重复的三元组。

示例:

复制代码
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

二、问题分析

本题的目标是从数组中找出所有三个数相加为 0 的组合。

关键挑战:

  1. 要确保三元组不重复(即 [a,b,c][b,a,c] 要被视为相同)。
  2. 需要高效地搜索组合,不能使用简单的三重循环暴力法(O(n³))。

三、思路图解

我们可以将问题的思路用一个流程图展示:

小于0
大于0
输入数组 nums
排序 nums
固定第一个数 i: nums[i]
使用双指针 left、right 搜索剩余两个数
nums[i] + nums[left] + nums[right] == 0?
记录三元组并移动指针去重
left++ 增大和
right-- 减小和
返回所有不重复的结果

该算法的核心是:

  • 排序;
  • 固定一个数,用双指针解决两数之和问题;
  • 去重。

四、几种解法比较

1. 暴力三重循环法

思路:

遍历所有三元组组合并判断和是否为 0。

缺点:

  • 时间复杂度 O(n³)
  • 大量重复组合,需要去重处理。

复杂度:

  • 时间:O(n³)
  • 空间:O(n)

2. 排序 + 双指针法(推荐解法)

核心思想:

  1. 先排序。
  2. 遍历每个数,固定为第一个数 nums[i]
  3. [i+1, end] 范围内用左右指针寻找另外两个数,使三者之和为 0。
  4. 使用去重逻辑避免重复三元组。

算法步骤示意图:

< 0
> 0 排序数组
固定 nums[i]
left 指向 i+1, right 指向末尾
计算 sum = nums[i]+nums[left]+nums[right]
sum == 0?
加入结果并移动 left/right 去重
left++
right--

复杂度分析:

  • 时间复杂度:O(n²)
  • 空间复杂度:O(1)(不计结果存储)

3. 哈希辅助法(改进版本)

思路:

  • 固定一个数 nums[i],然后用 HashSet 查找是否存在 -nums[i] = nums[j] + nums[k]
  • 相对双指针法,不如排序法直观,且去重复杂。

复杂度:

  • 时间:O(n²)
  • 空间:O(n)

五、详细复杂度分析

解法 时间复杂度 空间复杂度 是否易去重 是否推荐
暴力法 O(n³) O(n)
排序+双指针 O(n²) O(1) ✅ 推荐
哈希辅助 O(n²) O(n) 较复杂 可考虑

六、Java代码实现(排序 + 双指针)

java 复制代码
import java.util.*;

public class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums); // 先排序
        int n = nums.length;

        for (int i = 0; i < n; i++) {
            // 去重:当 nums[i] == nums[i-1] 时跳过
            if (i > 0 && nums[i] == nums[i - 1]) continue;

            int left = i + 1;
            int right = n - 1;

            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];

                if (sum == 0) {
                    res.add(Arrays.asList(nums[i], nums[left], nums[right]));

                    // 移动指针去重
                    while (left < right && nums[left] == nums[left + 1]) left++;
                    while (left < right && nums[right] == nums[right - 1]) right--;

                    left++;
                    right--;
                } else if (sum < 0) {
                    left++;
                } else {
                    right--;
                }
            }
        }

        return res;
    }
}

总结

关键策略 说明
排序 有助于快速去重与双指针搜索
双指针 在 O(n²) 时间内实现两数和目标
去重 三种情况:固定数去重、左指针去重、右指针去重

本题是二维双指针的经典应用,也是理解 "两数之和" 到 "三数之和" 的自然延伸。

相关推荐
MicroTech20254 分钟前
微算法科技(NASDAQ :MLGO)抗量子区块链技术:筑牢量子时代的数字安全防线
科技·算法·区块链
Ivanqhz6 分钟前
图着色寄存器分配算法(Graph Coloring)
开发语言·javascript·python·算法·蓝桥杯·rust
Elsa️7468 分钟前
洛谷p5718 复习下快速排序和堆排序
数据结构·算法·排序算法
Frostnova丶11 分钟前
LeetCode 3567.子矩阵的最小绝对差
算法·leetcode·矩阵
夏日听雨眠12 分钟前
文件学习9
数据结构·学习·算法
华农DrLai12 分钟前
什么是自动Prompt优化?为什么需要算法来寻找最佳提示词?
人工智能·算法·llm·nlp·prompt·llama
黎阳之光13 分钟前
十五五智赋新程 黎阳之光以AI硬核技术筑造产业数智底座
大数据·人工智能·算法·安全·数字孪生
2401_8914821714 分钟前
C++中的原型模式
开发语言·c++·算法
皙然15 分钟前
深度解析三色标记算法:JVM 并发 GC 的核心底层逻辑
java·jvm·算法
sali-tec17 分钟前
C# 基于OpenCv的视觉工作流-章40-特征找图
图像处理·人工智能·opencv·算法·计算机视觉