news 2026/3/14 3:48:08

LeetCode 第 15 题:三数之和

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 第 15 题:三数之和

三数之和:从 “暴力狂” 到 “双指针大师” 的修炼之路 🚀

一、LeetCode 第 15 题:三数之和

先来看看LeetCode上给出的题目描述:

给你一个整数数组nums,判断是否存在三元组[nums[i], nums[j], nums[k]]满足i != ji != kj != 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

是不是看起来有点绕?别急,咱们从简单的开始盘,一步步搞定这个 “磨人小妖精”~

二、回顾两数之和:小试牛刀的开胃菜 🍴

在啃 “三数之和” 这块硬骨头前,必须先回味一下前面学过的 —— 两数之和。

1、暴力拆解:简单但 “费时间” 的莽夫做法 🤯

两数之和要找两个数加起来等于目标值,暴力法的思路特直接:拿每个数跟它后面的数挨个配对,看和是不是目标值。

代码长这样:

javascript

function twoSum(nums, target) { for (let i = 0; i < nums.length; i++) { for (let j = i + 1; j < nums.length; j++) { if (nums[i] + nums[j] === target) { return [i, j]; } } } return []; }

这方法时间复杂度是 O (n²),就像在操场找两个人,挨个问 “你们俩加起来够不够 100 斤”,人多了真扛不住~

2、hashMap 求差:用空间换时间的 “小聪明” 💡

既然暴力法太费时间,咱换个思路:用哈希表存下每个数的位置,然后对每个数nums[i],直接算target - nums[i]是不是在哈希表里。

代码示例:

javascript

function twoSum(nums, target) { const map = new Map(); for (let i = 0; i < nums.length; i++) { const complement = target - nums[i]; if (map.has(complement)) { return [map.get(complement), i]; } map.set(nums[i], i); } return []; }

这招时间复杂度降到 O (n),空间复杂度 O (n),相当于给每个人发个名牌,找的时候直接按名字喊,效率瞬间飙升!

想要具体学习两数之和问题的同学可以看看我前面的文章:https://blog.csdn.net/2302_80706750/article/details/155208999?spm=1001.2014.3001.5501。

三、三数之和:升级打怪的正餐时间 🍲

两数之和搞定了,三数之和怎么搞?别急,咱们先从 “莽夫” 开始,再进化成 “智者”。

1、暴力拆解:三重循环的 “时间杀手” ⏳

最直接的想法:三个数嘛,那就三重循环,挨个试!

代码大概长这样:

javascript

function threeSum(nums) { const res = []; const len = nums.length; // 先排序方便去重(虽然暴力法去重麻烦,但先排个序看着舒服) nums.sort((a, b) => a - b); for (let i = 0; i < len - 2; i++) { // 跳过重复的i(暴力法去重的雏形) if (i > 0 && nums[i] === nums[i - 1]) continue; for (let j = i + 1; j < len - 1; j++) { if (j > i + 1 && nums[j] === nums[j - 1]) continue; for (let k = j + 1; k < len; k++) { if (k > j + 1 && nums[k] === nums[k - 1]) continue; if (nums[i] + nums[j] + nums[k] === 0) { res.push([nums[i], nums[j], nums[k]]); } } } } return res; }

但这时间复杂度是 O (n³),想象一下如果数组有 1000 个元素,那就是 10 亿次运算,电脑看了都得哭😭 显然这招在 LeetCode 上是会超时的,不能通过 LeetCode ,必须换思路!

2、双指针解法:排序 + 指针的 “黄金组合” 🌟

这才是解决三数之和的 “正道之光”!核心思路是:先排序,再固定一个数,剩下两个数用双指针找 —— 把三数问题降成两数问题,妙啊~

(1)第一步:排序!排序!排序!(重要的事说三遍)

为啥要排序?因为排序后:

  • 方便跳过重复元素(重复的数挨在一起,一眼就能看出来)
  • 能让双指针 “有规律地移动”(左边小右边大,和大了就左移右指针,和小了就右移左指针)

JavaScript 数组的sort()方法默认是按字符串排序的,所以必须传个比较函数:

javascript

// 升序排列(从小到大):a - b < 0 时,a在前b在后(不交换) nums.sort((a, b) => a - b); // 降序排列(从大到小):b - a < 0 时,b在前a在后(不交换) // nums.sort((a, b) => b - a);

比如[2,3,2,1,4,9]排序后就成了[1,2,2,3,4,9],是不是清爽多了?

(2)第二步:固定一个数,派出 “左右护法” 指针

固定一个起点i(从 0 开始),然后左指针lefti+1出发,右指针right从数组末尾出发,三者形成 “铁三角”。

(3)第三步:根据三数之和 “指挥” 指针移动

计算sum = nums[i] + nums[left] + nums[right]

  • 如果sum === 0:完美!加入结果集,然后让left右移、right左移,继续找下一组
  • 如果sum < 0:和太小了,让left右移找个大点的数
  • 如果sum > 0:和太大了,让right左移找个小点的数
(4)第四步:跳过重复元素,拒绝 “复制粘贴”

这是关键!不然答案里会有重复的三元组:

  • i:如果nums[i] === nums[i-1],说明和上一个起点一样,直接跳过(注意i > 0才跳,第一个元素不能跳)
  • left:找到一组解后,left右移时如果和前一个数一样,继续右移
  • right:找到一组解后,right左移时如果和后一个数一样,继续左移
(5)完整代码:双指针的 “实战演练”

javascript

function threeSum(nums) { // 先排序,升序排列方便操作 nums.sort((a, b) => a - b); const res = []; // 固定i,注意i最多到length-3(因为要留left和right的位置) for (let i = 0; i < nums.length - 2; i++) { // 跳过重复的起点i if (i > 0 && nums[i] === nums[i - 1]) { continue; } // 左右指针:left是i的下一个,right是数组末尾 let left = i + 1; let right = nums.length - 1; // 指针没相遇就继续找 while (left < right) { const sum = nums[i] + nums[left] + nums[right]; if (sum === 0) { // 找到一组解,加入结果 res.push([nums[i], nums[left], nums[right]]); // 移动指针继续找 left++; right--; // 跳过重复的left while (left < right && nums[left] === nums[left - 1]) { left++; } // 跳过重复的right while (left < right && nums[right] === nums[right + 1]) { right--; } } else if (sum < 0) { // 和太小,left右移找大点的数 left++; } else { // 和太大,right左移找小点的数 right--; } } } return res; }

这方法时间复杂度是 O (n²)(排序占 O (nlogn),循环占 O (n²)),空间复杂度 O (1) 或 O (n)(取决于排序算法),比暴力法可优雅太多了~

四、面试官可能会抛来的 “灵魂拷问” 🧐

  1. 为啥三数之和要先排序?答:排序不仅能方便去重(重复元素挨在一起),还能让双指针有规律地移动(根据和的大小调整指针方向),这是双指针解法的核心前提~
  2. 时间复杂度怎么算的?答:排序是 O (nlogn),外层循环 O (n),内层双指针循环 O (n),整体是 O (n²),比暴力法的 O (n³) 好太多啦~
  3. 去重逻辑为什么要那么写?比如i > 0才跳?答:因为i=0是第一个元素,前面没元素可比,直接跳就错啦;而i>0时如果和前一个一样,说明重复了,必须跳,否则会出现重复的三元组~
  4. 两数之和能用双指针吗?三数之和为啥不用哈希表?答:两数之和用哈希表更简单(O (n)),双指针也能用但需要先排序(O (nlogn));三数之和用哈希表去重太麻烦,双指针配合排序去重更优雅,所以选双指针~

五、结语:从 “会做” 到 “做好” 的修行 ✨

三数之和这道题,从暴力法的 “蛮干” 到双指针的 “巧解”,藏着一个很重要的编程思维:把复杂问题拆解成简单问题,再用合适的工具(排序、指针)优化

就像玩游戏,新手只会平 A,高手却会用技能连招~ 希望这篇文章能帮你搞懂三数之和的 “连招秘籍”,下次遇到类似问题,也能从容应对!

最后送大家一句话:刷题不在多,在于懂原理 —— 毕竟面试官要的不是 “做题机器”,而是 “会思考的灵魂” 呀~ 加油,未来的顶尖大佬们!💪

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/5 2:56:33

gpt-oss-20b + Ollama下载指南:一键启动本地大模型服务

gpt-oss-20b Ollama下载指南&#xff1a;一键启动本地大模型服务 在一台16GB内存的MacBook Air上&#xff0c;运行一个接近GPT-4能力的语言模型——这在过去几乎不可想象。然而今天&#xff0c;借助“gpt-oss-20b”与Ollama的组合&#xff0c;这一切已经变为现实。你不再需要A…

作者头像 李华
网站建设 2026/3/5 3:04:32

database-export:自动化数据库文档生成工具,7步告别手动编写时代

database-export&#xff1a;自动化数据库文档生成工具&#xff0c;7步告别手动编写时代 【免费下载链接】database-export 基于SpringBoot的开源数据库表结构导出word文档工具 项目地址: https://gitcode.com/gh_mirrors/da/database-export 在软件开发的生命周期中&am…

作者头像 李华
网站建设 2026/3/13 21:28:14

利用HunyuanVideo-Foley自动生成环境音效,提升视频沉浸感

利用HunyuanVideo-Foley自动生成环境音效&#xff0c;提升视频沉浸感 在短视频日均产量突破千万条的今天&#xff0c;一个看似微小却影响深远的问题浮出水面&#xff1a;大量用户拍摄的画面清晰、构图讲究&#xff0c;但播放时却“无声胜有声”——没有背景音、没有动作反馈、…

作者头像 李华
网站建设 2026/3/14 3:50:42

终极微服务权限管理:RuoYi-Cloud-Plus企业级开源方案

RuoYi-Cloud-Plus作为企业级微服务权限管理的终极解决方案&#xff0c;通过整合SpringCloud Alibaba、Dubbo3.0、Sa-Token等主流技术栈&#xff0c;为企业提供了一套完整的权限控制体系。该项目重写了RuoYi-Cloud所有功能&#xff0c;支持容器化部署和全方位技术升级&#xff0…

作者头像 李华
网站建设 2026/3/11 13:10:37

AI开发平台的十大高价值应用场景,CTO和老板必看清单

引言&#xff1a; 对于企业的技术决策者&#xff08;CTO&#xff09;和战略制定者&#xff08;老板&#xff09;而言&#xff0c;了解一项技术的全景应用比深究一个细节更重要。本文旨在成为一份实用的“决策清单”&#xff0c;系统性地盘点AI开发平台across the enterprise 的…

作者头像 李华
网站建设 2026/3/11 17:31:13

Docker从入门到放弃?不存在的!这份实战指南让你秒变容器老司机

最近总有朋友问我Docker到底是个啥&#xff0c;怎么用&#xff0c;感觉很高大上但又不知道从哪里下手。说实话&#xff0c;我刚开始接触Docker的时候也是一脸懵逼&#xff0c;各种概念搞得头大。不过用了几年下来&#xff0c;现在回头看&#xff0c;Docker真的是个好东西&#…

作者头像 李华