当前位置: 首页 > ops >正文

[优选算法专题一双指针——三数之和]

题目链接

LeetCode三数之和

题目描述

题目解析

一、问题核心与解题思路

问题:给定整数数组 nums,返回所有不重复的三元组 [a, b, c],满足 a + b + c = 0 且 a、b、c 对应数组中不同索引的元素。

核心难点

  1. 找到所有满足条件的三元组;
  2. 避免结果中出现重复的三元组。

解题思路:采用 「排序 + 双指针」 组合策略,具体步骤如下:

  1. 排序数组:为双指针查找和去重提供基础;
  2. 固定第一个元素:通过外层循环遍历每个可能的第一个元素 a = nums[i]
  3. 双指针找剩余两个元素:在内层用左右指针(left = i+1right = n-1)寻找 b 和 c,使得 a + b + c = 0
  4. 去重处理:对三个指针跳过重复元素,避免生成重复三元组。

注意:

在去重的操作中可以使用set去重,但是我们这里推荐,因set 去重虽然能实现功能,但会显著降低效率,且编写代码的复杂程度也会提升,违背了「三数之和」的最优解法思路。因此,更推荐通过排序 + 跳过重复元素的方式去重,既高效又简洁。

这里举例一个已经排过序的新数组:

我们先固定第一个数:

这里就转化成了和为sum的问题,这里的s就是这个固定的数的相反数。也就是:

所以这里解决步骤:

  1. 先对整个数组排序
  2. 固定一个数 a(这里有个小优化,后续介绍)
  3. 在该数后面的区间内,利用双指针算法快速找到两个数的和为 -a 的即可。

注意:这里只是找到了符合条件的情况,并没有去重。

接下来就是处理细节问题了,也就是去重确保所有符合条件的情况不落下。

二、关键逻辑与优化解析
  1. 排序的作用
    排序后:

    • 相同元素相邻,便于跳过重复值(去重核心);
    • 数组有序,可通过双指针高效调整三数之和的大小(左移减小、右移增大)。
  2. 外层循环的优化

    • if (nums[i] > 0) break
      排序后数组递增,若 nums[i] > 0,则 nums[left] 和 nums[right] 均 ≥ nums[i],三数之和必 > 0,无需继续循环。
    • if (i + 2 < n && nums[i] + nums[i+1] + nums[i+2] > 0) break
      对于当前 i,最小的可能组合是 nums[i] + nums[i+1] + nums[i+2](后两个是最小的剩余元素)。若此和 > 0,说明当前 i 及更大的 i 都无有效组合,直接退出。
  3. 双指针的移动逻辑

    • 当 sum == 0:找到有效三元组,加入结果后,需同时移动左右指针并跳过重复值(否则会生成相同三元组);
    • 当 sum < 0:和太小,左指针右移(增大 nums[left]);
    • 当 sum > 0:和太大,右指针左移(减小 nums[right])。
  4. 去重的关键细节

    三、完整代码

    • 对 i 去重:避免因固定元素重复导致的三元组重复(如 [-1, -1, 2] 与 [-1, -1, 2]);
    • 对 left 和 right 去重:找到一组解后,需跳过相邻的相同元素(如 [-2, 0, 0, 2, 2] 中,找到 [-2, 0, 2] 后需跳过重复的 0 和 2)。
四、常见错误点
  1. 越界问题
    需确保 i + 2 < n 再判断 nums[i] + nums[i+1] + nums[i+2],否则可能访问无效索引。

  2. 去重时机错误
    必须在找到有效三元组后再去重(如 sum == 0 时),不能提前去重,否则可能漏掉合法解。

  3. 指针移动遗漏
    找到有效解后,需同时移动 left 和 right(而非只移动一个),否则可能陷入死循环。

五、复杂度分析
  • 时间复杂度

    • 排序:O(n log n)
    • 外层循环 O(n) + 内层双指针 O(n),整体为 O(n²)
      总时间复杂度:O(n²)(排序可忽略)。
  • 空间复杂度

    • 除结果存储外,仅使用常数级额外空间(指针、临时变量),故为 O(1)(若考虑排序的栈空间,最坏为 O(log n))。

http://www.xdnf.cn/news/17310.html

相关文章:

  • Python训练营打卡Day26-函数专题2:装饰器
  • 最长回文子串
  • 远期(Forward)交易系统全球金融市场解决方案报告
  • Java 之 设计模式
  • Python名称映射技术:基于序列元素的高级访问模式详解
  • [科普] AI加速器架构全景图:从GPU到光计算的算力革命
  • 豆包新模型+PromptPilot:AI应用开发全流程实战指南
  • 【C++高阶五】mapset对红黑树的封装
  • Nestjs框架: 接口安全与响应脱敏实践 --- 从拦截器到自定义序列化装饰器
  • 【昇腾】Atlas 500 A2 智能小站制卡从M.2 SATA盘启动Ubuntu22.04系统,重新上电卡死没进系统问题处理_20250808
  • 大语言模型提示工程与应用:提示词基础使用方式
  • Redis原理,命令,协议以及异步方式
  • 分布式膛压应变测量系统
  • 中国电信清华:大模型驱动的具身智能发展与挑战综述
  • BGP综合实验
  • 代码随想录算法训练营第三十八天、三十九天|动态规划part11、12
  • 考研复习-计算机组成原理-第四章-指令系统
  • 机器人焊机智能流量调节
  • 内容分发机制研究:实测一款多源短视频聚合App
  • isulad + harbor私有仓库登录
  • 从安卓兼容性困境到腾讯Bugly的救赎:全链路崩溃监控解决方案-卓伊凡|bigniu
  • 机器学习概念1
  • STM32HAL 快速入门(二):用 CubeMX 配置点灯程序 —— 从工程生成到 LED 闪烁
  • 服务器登上去,显示 failed to send WATCHDOG 重启有效吗?
  • Android 之 ANR问题的全面解析与优化方案
  • Godot ------ 制作属于自己的卡牌
  • 讲一讲@ImportResource
  • C++ WonderTrader源码分析之自旋锁实现
  • 宁商平台税务新举措:合规护航,服务暖心
  • 视频质量检测中准确率↑32%:陌讯多模态评估方案实战解析