LeetCode-day5:三数之和

📘 从暴力到优雅:我在「三数之和」中学到的三大算法思维

题目 :LeetCode #15 ------ 三数之和(3Sum)
关键词:双指针|排序去重|固定一数转两数之和|结果收集技巧


一、我的起点:想用暴力,却被现实打脸

刚开始看到「三数之和」,我的第一反应是:

"不就是三层 for 循环吗?遍历所有 i < j < k 的组合,加起来等于 0 就行了。"

但很快我就意识到问题:

  • 时间复杂度 O(n³),数据一大就超时;
  • 更头疼的是------如何避免重复的三元组 ?比如 [-1, 0, 1][0, -1, 1] 其实是同一个答案。

我卡住了。直到我学到一个关键思想:

把"三数之和"转化为"固定一个数 + 两数之和"


二、核心突破:固定一个数,问题降维!

🔑 思路拆解

  1. 先对数组排序
    → 排序后,相同的数会挨在一起,为去重打下基础 ;同时,双指针才能生效
  2. 外层循环固定第一个数 nums[i]
    → 那么问题就变成了:在剩下的子数组中,找两个数,使得它们的和等于 -nums[i]
  3. 内层用双指针找"两数之和"
    • left = i + 1
    • right = n - 1
    • 如果 nums[left] + nums[right] == target → 找到一组解!
    • 如果和太小 → left++
    • 如果和太大 → right--

💡 这一步让我恍然大悟:复杂问题可以通过"固定变量"来降维

3Sum → 2Sum,4Sum → 3Sum → 2Sum......这是一个可扩展的模板!


三、结果怎么存?学会用 res = [] + append()

以前我总纠结"怎么返回多个列表",现在我知道了最 Pythonic 的方式:

python 复制代码
res = []  # 初始化空列表
...
res.append([a, b, c])  # 找到一组就加进去
...
return res
  • 简洁、直观、高效;
  • 不需要预分配空间,动态增长;
  • 最终直接返回这个列表即可。

append 是收集多组结果的黄金搭档


四、最难啃的骨头:去重!为什么不能偷懒?

本题最容易出错的地方,不是找数,而是去重

我曾想过:"能不能用 set 存 tuple 自动去重?"

技术上可以,但效率低、面试不加分,而且没抓住问题本质

正确做法:利用"排序后重复值相邻"的特性

去重点 1:跳过重复的 i
python 复制代码
if i > 0 and nums[i] == nums[i-1]:
    continue

→ 避免以相同的数作为起点,产生重复三元组。

去重点 2:找到解后,跳过重复的 leftright
python 复制代码
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

→ 确保下一组 (left, right) 是全新的组合。

🌟 去重的本质不是"事后过滤",而是"事前跳过"

在有序数组中,这是最高效的方式。


五、我的完整代码(带注释)

python 复制代码
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()          # 第一步:排序
        res = []             # 初始化结果列表
        n = len(nums)
        
        for i in range(n - 2):
            # 跳过重复的 i
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            
            target = -nums[i]
            left, right = i + 1, n - 1
            
            while left < right:
                s = nums[left] + nums[right]
                if s == target:
                    res.append([nums[i], nums[left], nums[right]])
                    
                    # 跳过重复的 left 和 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 s < target:
                    left += 1
                else:
                    right -= 1
        
        return res

六、总结:我带走的三大收获

收获 说明
1. 结果收集模式 res = [] + res.append(...) 动态收集答案
2. 降维思想 固定一个数,将 K 数之和转化为 (K-1) 数之和
3. 主动去重策略 利用排序 + 相邻比较,在过程中跳过重复,而非事后过滤
相关推荐
吃好睡好便好5 小时前
在Matlab中绘制横直方图
开发语言·学习·算法·matlab
仰泳之鹅5 小时前
【C语言】自定义数据类型2——联合体与枚举
c语言·开发语言·算法
x_yeyue8 小时前
三角形数
笔记·算法·数论·组合数学
念何架构之路9 小时前
Go语言加密算法
数据结构·算法·哈希算法
AI科技星9 小时前
《数学公理体系·第三部·数术几何》(2026 年版)
c语言·开发语言·线性代数·算法·矩阵·量子计算·agi
失去的青春---夕阳下的奔跑9 小时前
560. 和为 K 的子数组
数据结构·算法·leetcode
黎阳之光9 小时前
黎阳之光:以视频孪生重构智慧医院信息化,打造高标项目核心竞争力
大数据·人工智能·物联网·算法·数字孪生
丷丩10 小时前
三级缓存下MVT地图瓦片服务性能优化策略
算法·缓存·性能优化·gis·geoai-up
m0_6294947310 小时前
LeetCode 热题 100-----25.回文链表
数据结构·算法·leetcode·链表
ʚ希希ɞ ྀ11 小时前
单词拆分----dp
算法