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. 主动去重策略 利用排序 + 相邻比较,在过程中跳过重复,而非事后过滤
相关推荐
珂朵莉MM10 分钟前
全球校园人工智能算法精英大赛-产业命题赛-算法巅峰赛 2025年度画像
java·人工智能·算法·机器人
Morwit18 分钟前
*【力扣hot100】 647. 回文子串
c++·算法·leetcode
tobias.b42 分钟前
408真题解析-2009-13-计组-浮点数加减运算
算法·计算机考研·408考研·408真题
菜鸟233号1 小时前
力扣96 不同的二叉搜索树 java实现
java·数据结构·算法·leetcode
Coovally AI模型快速验证2 小时前
超越Sora的开源思路:如何用预训练组件高效训练你的视频扩散模型?(附训练代码)
人工智能·算法·yolo·计算机视觉·音视频·无人机
千金裘换酒2 小时前
Leetcode 有效括号 栈
算法·leetcode·职场和发展
空空潍2 小时前
hot100-最小覆盖字串(day12)
数据结构·算法·leetcode
Rui_Freely2 小时前
Vins-Fusion之 相机—IMU在线标定(十一)
人工智能·算法·计算机视觉
yyy(十一月限定版)2 小时前
算法——二分
数据结构·算法