1. LeetCode刷题第8天:我的算法进阶之路
作为一名程序员,算法能力的重要性不言而喻。去年我开始系统性地刷LeetCode,今天是坚持的第8天。与大多数人不同,我选择了一条"少而精"的路线——每天只深入研究1-2道中等难度题目,但确保完全吃透每个细节。这种策略让我在短短一周内就感受到了明显的进步。
2. 今日题目解析:两数之和的进阶版
2.1 题目重述与初步分析
今天选择的是第15题"三数之和"。题目要求:给定一个包含n个整数的数组nums,判断nums中是否存在三个元素a,b,c,使得a+b+c=0?找出所有不重复的三元组。
乍看之下,这像是经典"两数之和"的扩展版,但实际复杂度呈指数级增长。我的第一反应是暴力解法——三重循环枚举所有可能的三元组,时间复杂度O(n³)。这在LeetCode上肯定超时,必须寻找更优解。
2.2 排序与双指针的巧妙结合
经过思考,我决定先对数组排序(O(nlogn)),这是很多数组类题目的预处理技巧。排序后,固定第一个数nums[i],问题就转化为在i+1到n-1的范围内寻找两数之和等于-nums[i],这正是双指针的用武之地。
具体实现时,需要注意几个关键点:
- 去重处理:当nums[i] == nums[i-1]时需要跳过,避免重复解
- 提前终止:如果nums[i] > 0,由于数组已排序,后面不可能有三数之和为0
- 双指针移动:当sum < 0时移动左指针,sum > 0时移动右指针
python复制def threeSum(nums):
nums.sort()
res = []
n = len(nums)
for i in range(n-2):
if nums[i] > 0: break
if i > 0 and nums[i] == nums[i-1]: continue
l, r = i+1, n-1
while l < r:
s = nums[i] + nums[l] + nums[r]
if s < 0:
l += 1
elif s > 0:
r -= 1
else:
res.append([nums[i], nums[l], nums[r]])
while l < r and nums[l] == nums[l+1]: l += 1
while l < r and nums[r] == nums[r-1]: r -= 1
l += 1
r -= 1
return res
2.3 边界条件与特殊测试用例
在实际编码中,我遇到了几个容易忽略的边界情况:
- 输入数组长度小于3时应直接返回空列表
- 全零数组[0,0,0]是合法解
- 包含重复元素如[-1,-1,0,1]需要正确处理
- 大数组测试(LeetCode上的极端用例)
提示:在提交前,务必手动测试这些边界情况。我在第一次提交时就因为漏掉了数组长度检查而WA(Wrong Answer)。
3. 算法优化:从O(n³)到O(n²)
3.1 时间复杂度分析
暴力解法的时间复杂度是O(n³),而优化后的算法:
- 排序:O(nlogn)
- 外层循环:O(n)
- 内层双指针:O(n)
总体复杂度为O(nlogn) + O(n²) = O(n²)
这在n较大时(如LeetCode的3000个元素测试用例)优势明显。实际测试中,优化后的解法能在200ms内完成,而暴力解法直接超时。
3.2 空间复杂度考量
除了时间复杂度,空间复杂度也是面试常考点。该算法除了存储结果的列表外,只使用了常数级别的额外空间(几个指针变量),因此空间复杂度是O(1)(不考虑输出占用的空间)。
4. 刷题心得与实用技巧
4.1 我的LeetCode刷题方法论
经过8天的实践,我总结出一套有效的刷题方法:
- 先独立思考15-20分钟,写出伪代码
- 对比讨论区的高赞解法,找出思维差异
- 手写实现并提交,记录执行时间和内存消耗
- 第二天复习前一天的题目,尝试不同解法
4.2 调试与性能分析的实用工具
在本地调试时,我推荐使用:
- Python的timeit模块测量函数执行时间
- memory_profiler分析内存使用情况
- LeetCode的playground功能快速测试不同用例
例如,可以用以下方式测试三数之和的性能:
python复制import timeit
setup_code = """
from __main__ import threeSum
nums = [-1,0,1,2,-1,-4]*100 # 制造大数据量
"""
print(timeit.timeit('threeSum(nums)', setup=setup_code, number=100))
4.3 常见错误与修正方法
新手常犯的几个错误:
- 忘记处理重复三元组(需要排序+跳过相同元素)
- 双指针移动逻辑错误(应先记录有效解再移动指针)
- 边界条件检查不完整(空数组、全零数组等)
我在第3次提交时才AC(Accepted),前两次分别因为:
- 没有跳过nums[i] == nums[i-1]的情况
- 在找到有效解后,只移动了一个指针导致漏解
5. 同类题目拓展练习
为了巩固这个技巧,我找了几道相似题目练习:
- 最接近的三数之和(LeetCode 16)
- 四数之和(LeetCode 18)
- 较小的三数之和(LintCode 918)
特别是"四数之和",可以套用相同的思路:固定前两个数,然后用双指针找后两个数。这种"降维"思想在解决n数之和问题时非常有用。
6. 算法学习资源推荐
对于想系统学习算法的小伙伴,我推荐:
- 《算法导论》——理论基础必备
- 《剑指Offer》——面试高频题精讲
- LeetCode探索栏目——分类学习路线
- 可视化算法网站(如visualgo.net)——直观理解算法执行过程
坚持每天刷题确实不易,但8天下来,我明显感觉到自己分析问题的能力提升了。以前看到题目就发懵,现在至少能有条理地思考可能的解法方向。记住:刷题不在多而在精,理解每道题背后的算法思想才是关键。
