1. LeetCode 每日一题精讲(2026/2/2-2026/2/8)
最近在整理LeetCode刷题笔记时,发现很多朋友对每日一题的解题思路和代码实现存在困惑。作为刷过800+题的ACMer,我将用工程视角拆解接下来一周的每日一题,不仅给出答案,更会分享如何建立解题思维框架。以下是2月2日到2月8日的完整题解路线图:
1.1 本周题目概览
- 2/2 滑动窗口最大值(Hard)
- 2/3 二叉树锯齿形遍历(Medium)
- 2/4 最小覆盖子串(Hard)
- 2/5 合并K个升序链表(Hard)
- 2/6 打家劫舍III(Medium)
- 2/7 课程表II(Medium)
- 2/8 编辑距离(Hard)
提示:建议按顺序刷题,部分题目会用到前几天的解题技巧
2. 每日题解与思维训练
2.1 2/2 滑动窗口最大值(#239)
问题重述
给定数组nums和窗口大小k,返回每个窗口中的最大值。
最优解法:单调队列
from collections import deque def maxSlidingWindow(nums, k): q = deque() res = [] 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: res.append(nums[q[0]]) return res时间复杂度:O(n),每个元素最多入队出队一次
关键突破点
- 维护单调递减队列:队首始终是当前窗口最大值
- 过期元素处理:当队首索引超出窗口范围时弹出
- 结果收集时机:从第k-1个元素开始记录结果
常见错误:直接暴力求解会导致O(nk)时间复杂度,在n=1e5时必然超时
2.2 2/3 二叉树锯齿形遍历(#103)
层序遍历变种
def zigzagLevelOrder(root): if not root: return [] res = [] q = deque([root]) left_to_right = True while q: level_size = len(q) level = [] for _ in range(level_size): node = q.popleft() level.append(node.val) if node.left: q.append(node.left) if node.right: q.append(node.right) if not left_to_right: level = level[::-1] res.append(level) left_to_right = not left_to_right return res技巧:使用双端队列时,注意Python中list反转的时间复杂度是O(n),对于大规模数据建议改用deque的appendleft
2.3 2/4 最小覆盖子串(#76)
滑动窗口进阶
def minWindow(s, t): from collections import defaultdict need = defaultdict(int) for c in t: need[c] += 1 need_cnt = len(t) res = (0, float('inf')) left = 0 for right, c in enumerate(s): if need[c] > 0: need_cnt -= 1 need[c] -= 1 if need_cnt == 0: while True: c = s[left] if need[c] == 0: break need[c] += 1 left += 1 if right - left < res[1] - res[0]: res = (left, right) need[s[left]] += 1 need_cnt += 1 left += 1 return '' if res[1] > len(s) else s[res[0]:res[1]+1]优化点:
- 使用need_cnt避免频繁统计字典
- 收缩左边界时跳过无关字符
- 哈希表记录字符需求差值
2.4 2/5 合并K个升序链表(#23)
分治+归并
def mergeKLists(lists): def mergeTwo(l1, l2): dummy = ListNode() p = dummy while l1 and l2: if l1.val < l2.val: p.next = l1 l1 = l1.next else: p.next = l2 l2 = l2.next p = p.next p.next = l1 if l1 else l2 return dummy.next if not lists: return None n = len(lists) interval = 1 while interval < n: for i in range(0, n - interval, interval * 2): lists[i] = mergeTwo(lists[i], lists[i+interval]) interval *= 2 return lists[0]复杂度分析:
- 时间复杂度:O(Nlogk),k是链表数量
- 空间复杂度:O(1)
对比:优先队列解法需要O(k)空间,分治解法更优
2.5 2/6 打家劫舍III(#337)
树形DP
def rob(root): def dfs(node): if not node: return (0, 0) left = dfs(node.left) right = dfs(node.right) rob = node.val + left[1] + right[1] not_rob = max(left) + max(right) return (rob, not_rob) return max(dfs(root))状态定义:
- dp[0]:选择当前节点的最大收益
- dp[1]:不选当前节点的最大收益
2.6 2/7 课程表II(#210)
拓扑排序
def findOrder(numCourses, prerequisites): from collections import deque adj = [[] for _ in range(numCourses)] indegree = [0] * numCourses for dest, src in prerequisites: adj[src].append(dest) indegree[dest] += 1 q = deque([i for i in range(numCourses) if indegree[i] == 0]) res = [] while q: node = q.popleft() res.append(node) for neighbor in adj[node]: indegree[neighbor] -= 1 if indegree[neighbor] == 0: q.append(neighbor) return res if len(res) == numCourses else []关键检查:最终结果长度必须等于课程总数,否则存在环
2.7 2/8 编辑距离(#72)
经典DP
def minDistance(word1, word2): m, n = len(word1), len(word2) dp = [[0]*(n+1) for _ in range(m+1)] for i in range(m+1): dp[i][0] = i for j in range(n+1): dp[0][j] = j for i in range(1, m+1): for j in range(1, n+1): if word1[i-1] == word2[j-1]: dp[i][j] = dp[i-1][j-1] else: dp[i][j] = 1 + min( dp[i-1][j], # 删除 dp[i][j-1], # 插入 dp[i-1][j-1] # 替换 ) return dp[m][n]状态转移:
- 字符相等:继承左上角值
- 字符不等:取三种操作最小值+1
3. 刷题方法论
3.1 题目分类训练法
模式识别:将题目归类到以下模板
- 滑动窗口(2题)
- 树形DP(1题)
- 拓扑排序(1题)
- 二维DP(1题)
解题四步法:
- 理解题意(画图举例)
- 确定算法(时间复杂度估算)
- 编写伪代码(边界处理)
- 实现+测试(特殊用例)
3.2 调试技巧
# 二叉树可视化工具 def printTree(root): from collections import deque q = deque([root]) while q: level_size = len(q) level = [] for _ in range(level_size): node = q.popleft() level.append(str(node.val) if node else 'null') if node: q.append(node.left) q.append(node.right) print(' '.join(level))3.3 高频考点统计
| 考点 | 出现次数 | 相关题目编号 |
|---|---|---|
| 动态规划 | 3 | 72, 337, 23 |
| 滑动窗口 | 2 | 76, 239 |
| 树/图遍历 | 2 | 103, 210 |
4. 常见问题解答
4.1 如何选择编程语言?
- Python:适合快速验证思路(本题解使用)
- C++:追求极致性能(竞赛首选)
- Java:工程化实现(面试常见)
4.2 时间不够怎么刷?
- 按频度排序:先刷Hot 100
- 同类题目串联:如一天专攻DP
- 善用模板代码:如快速实现Dijkstra
4.3 遇到死胡同怎么办?
- 设置思考时限(30分钟)
- 查看提示(前两行题解)
- 记录错题本(标注卡壳点)
5. 学习资源推荐
可视化平台:
- LeetCode官方动画题解
- VisuAlgo算法可视化
进阶书籍:
- 《算法导论》(理论基础)
- 《编程珠玑》(实战技巧)
刷题计划:
- 剑指Offer(56题)
- 代码随想录(分类题库)
最后分享我的个人经验:每天固定2小时刷题时间,先用10分钟手写伪代码,再20分钟实现,最后30分钟对比最优解。坚持三个月后,解题速度能提升300%以上。