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. 主动去重策略 利用排序 + 相邻比较,在过程中跳过重复,而非事后过滤
相关推荐
CodeByV9 分钟前
【算法题】多源BFS
算法
TracyCoder12312 分钟前
LeetCode Hot100(18/100)——160. 相交链表
算法·leetcode
浒畔居14 分钟前
泛型编程与STL设计思想
开发语言·c++·算法
独处东汉1 小时前
freertos开发空气检测仪之输入子系统结构体设计
数据结构·人工智能·stm32·单片机·嵌入式硬件·算法
乐迪信息1 小时前
乐迪信息:AI防爆摄像机在船舶监控的应用
大数据·网络·人工智能·算法·无人机
放荡不羁的野指针1 小时前
leetcode150题-滑动窗口
数据结构·算法·leetcode
小龙报1 小时前
【C语言进阶数据结构与算法】单链表综合练习:1.删除链表中等于给定值 val 的所有节点 2.反转链表 3.链表中间节点
c语言·开发语言·数据结构·c++·算法·链表·visual studio
三川6982 小时前
面试题目记录
面试·职场和发展
程序员杰哥2 小时前
性能测试详解
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·性能测试
TracyCoder1232 小时前
LeetCode Hot100(13/100)——238. 除了自身以外数组的乘积
算法·leetcode