LeetCode 15:三数之和 | 双指针法详解与进阶应用

news2026/5/22 2:01:59
LeetCode 15三数之和 | 双指针法详解与进阶应用引言三数之和3Sum是 LeetCode 中一道经典的高频面试题编号为 15属于 Medium 难度范畴。这道题的核心要求是在一个整数数组中找出所有不重复的三元组使得这三个数之和为零。由于其看似简单但实现细节丰富的特点三数之和成为了考察算法思维和代码实现能力的重要题目。三数之和的暴力解法时间复杂度为 O(n³)对于大规模数据显然无法接受。更优的解决方案采用双指针技巧将时间复杂度降低到 O(n²)同时通过巧妙的去重机制避免重复三元组的产生。本文将深入剖析双指针法解决三数之和的原理、实现细节以及各种边界情况的处理帮助读者彻底掌握这一经典问题的解题思路。问题分析题目描述给定一个整数数组 nums判断是否存在元素 a、b、c 使得 nums[i] nums[j] nums[k] 0i ≠ j、i ≠ k 且 j ≠ k并返回所有满足条件的不重复三元组。例如对于输入 [-1, 0, 1, 2, -1, -4]满足条件的三元组有 [[-1, -1, 2], [-1, 0, 1]]。问题特点三数之和问题具有以下几个显著特点使其成为算法学习中的经典案例。首先由于需要返回所有满足条件的三元组而不是仅仅判断是否存在因此需要穷举所有可能的组合。其次要求返回的三元组不能重复这意味着需要对结果进行去重处理。最后为了在 O(n²) 时间复杂度内解决此问题必须采用高效的搜索策略双指针法正是为此量身定做的技巧。从更宏观的角度看三数之和实际上是更广泛的 K 数之和问题的一个特例。当 K 大于 2 时可以通过递归的方式将 K 数之和问题转化为若干个 (K-1) 数之和问题但这种递归方法的时间复杂度会随着 K 的增大而指数增长。对于三数之和这一特殊情形双指针法提供了更为优雅和高效的解决方案。暴力解法分析考虑最直接的暴力解法我们可以使用三层嵌套循环遍历所有可能的三元组检查其和是否为零。这种方法的时间复杂度为 O(n³)空间复杂度为 O(1)。假设 n 为 1000那么需要执行约 10 亿次运算这对于现代计算机来说仍然是一个相当耗时的操作。更重要的是暴力解法会产生大量重复的三元组后续去重过程同样需要额外的时间和空间开销。双指针法原理排序预处理双指针法解决三数之和的第一步是对数组进行排序。排序的目的有两个一是通过将相等的元素聚集在一起方便后续的去重操作二是为双指针的移动提供方向性指导。排序后数组呈现非递减的顺序这意味着当指针指向某个元素时我们可以根据该元素与目标值的关系来决定指针的移动方向。排序操作的时间复杂度为 O(n log n)这是双指针法总时间复杂度 O(n²) 中不可忽视的一部分。虽然排序增加了时间成本但它为整个算法提供了重要的有序性保证使得后续的搜索过程可以更加高效地进行。需要注意的是排序会改变原有数组元素的相对位置但由于我们只需要返回满足条件的三元组而不需要知道这些三元组中元素的原始索引因此这种改变是无害的。固定一个数在排序后的数组中我们首先固定一个元素作为三元组中的第一个数。假设固定的是 nums[i]那么问题就转化为在剩余的 nums[i1] 到 nums[n-1] 范围内找到两个数使它们的和等于 -nums[i]。这一步将原问题从三数之和转化为两数之和问题而两数之和正是双指针法最经典的应用场景。对于 nums[i] 的选择我们需要特别注意去重。当 nums[i] 与前一个元素 nums[i-1] 相同时如果继续以 nums[i] 为第一个数进行搜索会产生与之前搜索重复的三元组。因此当我们遇到连续相同的元素时应该直接跳过将 i 移动到下一个不同元素的位置。这种去重策略是双指针法高效性的重要保障。两侧指针搜索在确定了固定的第一个数 nums[i] 后我们在 [i1, n-1] 区间内设置两个指针left 指向区间的左端点 i1right 指向区间的右端点 n-1。此时我们的目标是找到 nums[left] nums[right] -nums[i] 的情况。如果三数之和大于零说明需要减小总和由于数组已排序减小 right 指针可以减小 nums[right] 的值如果三数之和小于零说明需要增大总和增大 left 指针可以增大 nums[left] 的值。这一搜索过程持续进行直到 left 和 right 指针相遇此时我们已经检查了所有可能的二元组合。每次找到满足条件的三元组后需要将 left 和 right 指针都向中间移动并跳过所有与当前元素相同的值以避免产生重复的三元组。这种移动策略确保了每个不同的三元组只会被发现一次。完整代码实现from typing import List class Solution: def threeSum(self, nums: List[int]) - List[List[int]]: n len(nums) if n 3: return [] nums.sort() result [] for i in range(n - 2): if nums[i] 0: break if i 0 and nums[i] nums[i - 1]: continue left, right i 1, n - 1 target -nums[i] while left right: total nums[left] nums[right] if total target: result.append([nums[i], nums[left], nums[right]]) while left right and nums[left] nums[left 1]: left 1 while left right and nums[right] nums[right - 1]: right - 1 left 1 right - 1 elif total target: left 1 else: right - 1 return result上述实现中包含了几个关键的去重技巧。首先在外层循环中跳过与前一个元素相同的 nums[i]避免以相同的数字作为三元组的第一个元素。其次在找到一个满足条件的三元组后通过 while 循环跳过所有与 nums[left] 和 nums[right] 相同的元素避免产生重复的三元组。这些去重操作确保了最终返回的结果集中不包含任何重复的三元组。算法复杂度分析时间复杂度双指针法解决三数之和问题的时间复杂度为 O(n²)。这是因为外层循环最多遍历 n-2 次而每次内层的双指针搜索过程在最坏情况下也会移动 O(n) 次。具体来说外层循环的时间复杂度为 O(n)内层双指针搜索的时间复杂度同样为 O(n)两者相乘得到总时间复杂度 O(n²)。排序操作的时间复杂度 O(n log n) 在大 O 表示法中被更高级的 O(n²) 吸收因此最终的时间复杂度仍为 O(n²)。空间复杂度算法的空间复杂度为 O(1)不包括输出结果所占用的空间。这是因为双指针法只需要使用常数个额外变量来存储指针位置、中间计算结果等而不需要使用额外的数据结构来存储数组元素。返回的结果列表虽然占用了空间但在计算空间复杂度时通常不计入输出参数所占用的空间。边界情况处理空数组和短数组当输入数组的长度小于 3 时无论如何都无法组成三元组因此直接返回空列表。这是代码中最基本但也最容易忽略的边界检查。类似地当数组中所有元素都大于零时由于三个正数之和永远不可能为零可以提前终止外层循环这种优化在实际应用中可以显著减少不必要的计算。包含重复元素的数组去重是三数之和问题的核心难点之一。考虑输入 [-1, -1, -1, 2, 2, 2]如果不去重可能会产生多个相同的三元组 [-1, -1, 2]。去重策略的核心是当我们在遍历过程中遇到与前一个元素相同的值时直接跳过。这种策略基于一个重要的观察如果以相同的值作为三元组的第一个或第二个、第三个元素那么之前已经搜索过所有以该值开头的情况再次搜索只会产生重复结果。包含零的特殊情况零在这个问题中具有特殊意义因为 -nums[i] 本身可能为零。考虑输入 [-1, 0, 1, 2, -1, -4]其中存在 nums[j] 0 的情况。当 nums[i] nums[j] nums[right] 0 时意味着找到了一个包含零的三元组。由于零既不是正数也不是负数它不会影响排序后数组的单调性因此双指针的移动策略在包含零的情况下仍然有效。代码中对 nums[i] 0 的提前终止条件需要特别注意因为当 nums[i] 0 时即使后面的元素之和也为负三数之和仍可能为零。变种问题四数之和LeetCode 18四数之和是三数之和的直接扩展要求在数组中找到四个数之和等于目标值。最直观的解法是固定两个数然后使用双指针在剩余范围内寻找两个数使四数之和等于目标值。这种方法的时间复杂度为 O(n³)空间复杂度为 O(1)。另一种思路是使用哈希表将四数之和转化为两数之和问题但空间复杂度会增加。对于四数之和去重逻辑会更加复杂需要同时对四个位置进行去重处理。最接近的三数之和LeetCode 16最接近的三数之和问题要求找到三个数使它们的和最接近目标值。与原问题不同这里不需要精确等于目标值而是要找最接近的组合。解决这个问题可以在三数之和的基础上稍作修改在遍历过程中计算当前三数之和与目标值的差的绝对值如果这个值比之前记录的最小差值更小则更新结果。由于不需要精确相等双指针的移动策略保持不变但不需要进行去重操作。统计三数之和为特定值的情况数如果问题不是返回具体的三元组而是统计三数之和等于目标值的情况数那么可以去重优化专注于计数。这种变种问题在某些实际应用场景中更常见例如在统计分析中计算某种组合的总数。解决思路与标准三数之和类似但在找到满足条件的三元组后不是添加到结果集中而是增加计数器的值。实际应用场景三数之和问题看似是一个纯学术性的算法问题但它在许多实际应用场景中都有重要的应用价值。在数据分析领域三数之和可以用于查找满足特定条件的组合例如在金融数据分析中寻找收益为零的投资组合。在游戏开发中三数之和的变种可以用于计算游戏中的得分组合或技能搭配。在图像处理和计算机视觉中三数之和的思想也被用于特征匹配和三维重建等场景。此外双指针作为一种通用的问题解决技巧其应用范围远不止三数之和问题。在处理有序数组的两数之和、两数之积、滑动窗口等问题时双指针法都展现出了极高的效率。因此深入理解三数之和问题的解决思路对于提升整体算法能力具有重要意义。总结三数之和问题是一道经典的算法面试题它巧妙地将双指针技巧与去重策略结合在一起以 O(n²) 的时间复杂度解决了看似简单却细节丰富的问题。通过对这道题的学习我们不仅掌握了双指针法的核心原理还深入理解了处理重复元素的技巧。在实际面试中三数之和及其变种问题经常出现能够清晰准确地实现这道题的候选人往往能给面试官留下良好的印象。通过本文的详细讲解希望读者能够彻底掌握三数之和问题的解决方法并将其中的算法思想融会贯通应用于更多类似问题的解决中。双指针法作为一种强大的算法技巧值得我们在实践中不断加深理解和应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2633296.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…