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:找到解后,跳过重复的 left 和 right
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. 主动去重策略 利用排序 + 相邻比较,在过程中跳过重复,而非事后过滤
相关推荐
-dzk-几秒前
【多维动态规划】LC 64.最小路径和
算法·动态规划
垆边人似月.1 小时前
华为机试题 :字符串压缩
算法·华为
ggb喔1 小时前
52pojie 的图片工具:为什么无损转换后体积涨了 6 倍、照片方向还是歪的
图像处理·python·算法·计算机视觉·图形渲染·媒体
菜鸟~noob2331 小时前
【电子战】第25篇:自由空间、双射线与菲涅尔区【含matlab代码】
开发语言·算法·matlab
地平线开发者1 小时前
地平线征程6M YOLOv8s 部署
算法·自动驾驶
Run_Teenage1 小时前
算法:Manacher(马拉车)算法、中心扩展算法
算法
Tisfy2 小时前
LeetCode 0301.删除无效的括号:二进制枚举 / 回溯
算法·leetcode·字符串·题解·回溯·括号匹配·二进制枚举
Nil2082 小时前
leetcode 322零钱兑换
算法·leetcode·职场和发展
海绵宝宝转agent2 小时前
2026-10-9 leetcode100刷题+面经整理
笔记·算法·面试
yi0112 小时前
DAY24: LeetCode 167:两数之和 II|从暴力枚举到左右双指针
笔记·python·算法·leetcode·二分查找·双指针