1. LeetCode刷题笔记的价值与定位
作为一名在算法领域摸爬滚打多年的工程师,我始终认为LeetCode刷题笔记是技术人最实用的"武功秘籍"。不同于普通的题解,系统的刷题笔记应该包含解题思路的演进过程、多种解法的对比分析以及实际编码中的陷阱警示。我最近整理的这份"LeetCode刷题笔记2"特别聚焦于滑动窗口、二分查找等高频考察题型,其中滑动窗口最大值(LeetCode 239)和爱吃香蕉的狒狒(LeetCode 875)这两道经典题目尤其值得深入剖析。
提示:优质的刷题笔记不是简单的AC代码合集,而是记录思维过程的成长日记。建议每个题目都保留最初的错误解法作为反面教材。
2. 滑动窗口最大值的技术拆解
2.1 暴力解法与优化思路
滑动窗口最大值这道hard题目,暴力解法的时间复杂度是O(n*k),当k接近n时会退化为O(n²)。我在笔记本上记录了第一次尝试时写的双重循环代码:
python复制def maxSlidingWindow(nums, k):
result = []
for i in range(len(nums) - k + 1):
window = nums[i:i+k]
result.append(max(window))
return result
这个解法虽然直观,但在LeetCode上提交时会因为超时无法通过。通过分析可以发现,每次窗口滑动时都在重复计算最大值,存在明显的优化空间。
2.2 单调队列的精妙设计
经过查阅资料和反复尝试,最终采用了单调队列的解法。这里的关键是维护一个双向队列,保证队列头部始终是当前窗口的最大值:
python复制from collections import deque
def maxSlidingWindow(nums, k):
q = deque()
result = []
for i, num in enumerate(nums):
while q and nums[q[-1]] <= num:
q.pop()
q.append(i)
if q[0] == i - k:
q.popleft()
if i >= k - 1:
result.append(nums[q[0]])
return result
这个算法将时间复杂度优化到了O(n),空间复杂度是O(k)。在实际编码时特别要注意:
- 队列中存储的是索引而非值,便于判断元素是否在窗口外
- 添加新元素前要移除所有比它小的元素
- 需要检查队首元素是否已经超出窗口范围
2.3 不同语言实现的性能对比
在C++中使用deque的实现比Python更快,实测运行时间能减少30%左右。而Java的ArrayDeque在数据量较大时表现最优。这说明算法题不仅要掌握思路,还要了解不同语言标准库的实现特性。
3. 爱吃香蕉的狒狒的二分应用
3.1 问题抽象与建模
LeetCode 875这道题看似简单,实则考察了对二分查找的深刻理解。题目要求找到狒狒吃香蕉的最小速度K,使得能在H小时内吃完所有香蕉。我的第一版代码直接将K从1开始线性搜索:
python复制def minEatingSpeed(piles, H):
k = 1
while True:
hours = 0
for pile in piles:
hours += (pile + k - 1) // k
if hours <= H:
return k
k += 1
这个解法在遇到大数测试用例时会超时,比如piles=[1000000000], H=2的情况。
3.2 二分查找的变种应用
优化后的解法使用二分查找,将时间复杂度从O(nmax(pile))降到了O(nlog(max(pile))):
python复制def minEatingSpeed(piles, H):
left, right = 1, max(piles)
while left < right:
mid = (left + right) // 2
if sum((pile + mid - 1) // mid for pile in piles) <= H:
right = mid
else:
left = mid + 1
return left
这里有几个关键点需要注意:
- 搜索范围的左边界是1,右边界是最大堆的香蕉数
- 计算所需时间时要使用向上取整的技巧 (pile + mid - 1) // mid
- 当hours <= H时不能直接返回mid,而要继续搜索更小的可能解
3.3 边界条件的处理经验
在实际测试时,我发现当H等于piles长度时,最小速度应该是max(piles)而非sum(piles)/H。这个边界条件很容易被忽略,建议在笔记中用红色标注这类特殊case。
4. LeetCode周赛的实战技巧
4.1 周赛430的题目分析
最近参加的周赛430中,第三题考察了前缀和与哈希表的组合应用。我的笔记记录了比赛时的思考过程:
- 首先尝试暴力解法,发现O(n²)复杂度无法通过
- 观察到子数组和可以表示为前缀和之差
- 使用哈希表记录前缀和的出现次数
- 特别注意处理前缀和为0的特殊情况
4.2 比赛时的调试技巧
在紧张的比赛环境中,我总结了几个调试技巧:
- 先写暴力解法确保理解题意正确
- 用小规模测试用例验证优化算法的正确性
- 对于边界条件,专门编写测试函数快速验证
- 使用print调试时添加有意义的标签,如print(f"i={i}, sum={curr_sum}")
4.3 时间管理策略
对于90分钟的比赛,我的时间分配建议是:
- 第一题:5-10分钟(简单题要快速AC)
- 第二题:15-20分钟(中等题要一次写对)
- 第三题:30分钟(可能有多种解法)
- 第四题:剩余时间尝试(hard题部分得分也很重要)
5. 热门100题的刷题路线
5.1 题目分类与优先级
根据我的刷题经验,LeetCode热门100题可以按以下顺序攻克:
- 数组与字符串操作(20题)
- 链表与指针技巧(15题)
- 树与图的遍历(20题)
- 动态规划(25题)
- 其他高级算法(20题)
5.2 每日刷题计划示例
这是我正在执行的30天强化计划:
code复制Day1-5:数组双指针技巧
- 两数之和、三数之和
- 盛最多水的容器
- 移动零
Day6-10:滑动窗口
- 无重复字符的最长子串
- 最小覆盖子串
- 找到字符串中所有字母异位词
5.3 错题本的建立方法
我使用Notion建立了数字错题本,每个题目记录:
- 初次解题思路
- 遇到的错误类型(边界条件、算法选择等)
- 最优解的分析过程
- 同类题目的关联索引
6. 刷题中的常见陷阱
6.1 内存越界问题
在使用双指针时,特别容易出现数组越界。例如在二分查找中,我曾经多次写出这样的错误代码:
python复制while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
left = mid # 应该是left = mid + 1
else:
right = mid # 应该是right = mid - 1
6.2 浮点数精度问题
在涉及浮点数比较时,直接使用==可能会出错。应该定义误差范围:
python复制def equal(a, b):
return abs(a - b) < 1e-6
6.3 递归爆栈问题
当树的深度很大时,递归解法可能导致栈溢出。比如二叉树的最大深度问题,虽然递归写法简洁:
python复制def maxDepth(root):
if not root:
return 0
return 1 + max(maxDepth(root.left), maxDepth(root.right))
但在实际工程中更推荐使用迭代的BFS或DFS实现。
7. 高效刷题的工作流
7.1 IDE配置技巧
我使用VS Code配置了LeetCode插件,并设置了以下快捷键:
- Ctrl+Alt+C:提交代码
- Ctrl+Alt+T:测试当前代码
- Ctrl+Alt+N:新建解题文件
7.2 本地测试框架
为了快速验证多个测试用例,我编写了简单的测试框架:
python复制def test(func, cases):
for i, (input, expected) in enumerate(cases):
result = func(*input)
assert result == expected, f"case {i} failed: {result} != {expected}"
print("All tests passed!")
test_cases = [
(([2,7,11,15], 9), [0,1]),
(([3,2,4], 6), [1,2])
]
test(twoSum, test_cases)
7.3 性能分析工具
对于时间复杂度存疑的代码,我使用Python的timeit模块进行测量:
python复制import timeit
setup = "from __main__ import sliding_window_max"
stmt = "sliding_window_max([1,3,-1,-3,5,3,6,7], 3)"
print(timeit.timeit(stmt, setup, number=10000))
在刷题过程中,我最大的体会是:不要满足于AC,要追求最优解;不要死记硬背,要理解算法本质;不要孤立刷题,要建立知识网络。每次遇到新题目时,先思考它属于哪种模式(滑动窗口、前缀和、DFS等),再套用相应的解题框架,这样效率会大大提高。
