注册一亩三分地论坛,查看更多干货!
您需要 登录 才可以下载或查看附件。没有帐号?注册账号 
x
求加米核心信念:LeetCode 考的不是"你背了多少题",而是"你能不能把一道没见过的题,映射到你见过的模式上"。 刷 1000 道题却不总结,不如吃透 15 个模式 + 一套固定流程。这篇讲的就是那套流程。
为什么需要框架
大多数人刷题的失败模式是这样的:读完题 → 盯着屏幕 → 凭直觉写 → 卡住 → 看答案 → "哦原来是这样" → 换一道题又不会。
问题不在于智商,而在于没有可复用的流程。真正稳定的解题者,脑子里跑的是一套几乎机械化的步骤:先分类,再套模板,最后验证。这篇文章把这套流程拆成三层:. 1point 3 acres
- 五步解题流程——从读题到 AC 的固定动作序列;
- 两张速查表——从"约束条件"反推复杂度,从"题目信号"反推模式;
- 核心模式模板——十几个模式的 Python 骨架,背下来就能套。
第一层:五步解题流程
把每道题都当成同一个流水线来处理。面试时尤其重要——面试官看的不是你多快写完,而是你思考是否有章法。. 1point3acres
第 1 步 · 读题与澄清(Understand)
不要急着写。先做四件事:
- 复述题目:用自己的话把题目讲一遍,确认理解没跑偏(面试中直接说出来)。
- 明确输入输出:数据类型是什么?有没有空输入、负数、重复元素?返回值是索引还是值?
- 看约束条件:有多大?数值范围?这一步直接决定了你的目标复杂度(见第二层速查表)。
- 手举一个例子:拿一个小例子走一遍,确认自己真的懂题意。再想一个边界例子(空、单元素、全相同)。
面试信号:主动问 clarifying question("数组可以为空吗?""有重复吗?")本身就是加分项。 第 2 步 · 定位模式(Match)
这是最关键的一步,决定了后面所有动作。问自己:用第二层的"信号 → 模式"速查表去匹配。90% 的题目会落在十几个模式里。如果一眼看不出来,先想暴力解——暴力解往往会暴露出结构("我在重复计算子问题" → DP;"我在枚举所有组合" → 回溯)。
第 3 步 · 设计思路(Plan)
- 先说暴力解:明确它的复杂度。哪怕最终不用,它也是你的 baseline,面试中先给暴力解永远是安全的。
- 再优化:暴力解的瓶颈在哪?能不能用哈希表把 O(n) 查找降到 O(1)?能不能用双指针省掉一层循环?能不能缓存子问题(DP)?
- 用例子验证思路:在写代码前,拿第 1 步的例子在纸上/口头把算法走一遍。如果思路在例子上都跑不通,代码一定错。
第 4 步 · 编码(Implement).
- 套对应模式的模板(第三层),别从零发明。
- 变量命名清晰,先写主干再补细节。
- 一边写一边讲你在干什么(面试中不要沉默写代码)。
第 5 步 · 验证与复杂度(Review)
- 手动 dry run:拿正常例子 + 边界例子逐行走一遍,别信"感觉对"。
- 边界检查清单:空输入、单元素、全相同、最大规模、负数/溢出。
- 报出复杂度:时间和空间,一定要主动说,并解释为什么。
第二层:两张速查表
速查表 A:从约束条件反推复杂度
这是被严重低估的技巧。约束里的直接告诉你目标复杂度,从而反推该用什么模式。看到就应该立刻在心里定位:. 1point3acres.com
的规模
| 可接受的复杂度
| 典型模式
| | 、 | 全排列回溯
| | | 子集枚举、状压 DP(bitmask)
| | | 区间 DP、Floyd 最短路
| | | 二维 DP、暴力双循环
| | | 排序、二分、堆、滑动窗口
| | | 一次扫描、双指针、哈希、前缀和
| | 或 | 二分答案、数学公式
|
实战用法:看到,几乎可以断定是状压/回溯;看到却想写,立刻知道会 TLE,必须优化到。 速查表 B:从题目信号反推模式
题目信号
| 模式. 1point 3acres
| 典型复杂度
| 有序数组里找目标 / 找一对数
| 二分查找 / 双指针
| / | 连续
子数组 / 子串的最优值或计数
| 滑动窗口
| | "所有"组合 / 排列 / 子集.
| 回溯
| / | "有多少种方式" / 最优代价,且有重叠子问题
| 动态规划
| 视题而定
| 树 / 图的遍历、连通性
| DFS / BFS
| | 无权图
最短路径
/ 最少步数
| BFS
| | Top K / 第 K 大 / 数据流中位数. 1point 3acres
| 堆(heap)
| | 下一个更大 / 更小元素、柱状图接雨水
| 单调栈
| | 区间合并 / 重叠判断-baidu 1point3acres
| 排序 + 扫描
| | 链表找环 / 找中点
| 快慢指针
| | 动态合并集合 / 判断连通
| 并查集(Union-Find)
| | 子数组和 / 区间和
| 前缀和 + 哈希
| | 网格里的岛屿 / 连通区域
. ---- | Flood Fill(DFS/BFS)
| | 大量字符串前缀查询
| 字典树(Trie) ..
| | 需要 O(1) 判断是否存在 / 计数
| 哈希表 / 集合
| | 求 k 个有序结构的合并
| 堆 / 分治.
| |
. .и
第三层:核心模式模板(Python)
背下这些骨架,遇到对应模式直接套。以下都是可以当"肌肉记忆"的写法。
1. 双指针(有序数组找一对)
def two_sum_sorted(nums, target):
lo, hi = 0, len(nums) - 1
while lo < hi:
s = nums[lo] + nums[hi]
if s == target:
. return [lo, hi]
elif s < target:. 1point3acres
lo += 1 # 和太小,左指针右移
else:
hi -= 1 # 和太大,右指针左移
return []
2. 快慢指针(链表找环)
def has_cycle(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:. From 1point 3acres bbs
return True
return False
3. 滑动窗口(变长窗口). 1point3acres.com
from collections import defaultdict
def longest_valid_window(s):
window = defaultdict(int)
left = 0.
res = 0
for right, c in enumerate(s):
window[c] += 1
# 窗口不合法时,从左边收缩
.1point3acres while not is_valid(window):
window[s[left]] -= 1
left += 1
res = max(res, right - left + 1)
return res
4. 二分查找(含"二分答案"心法)
def binary_search(nums, target): ..
lo, hi = 0, len(nums) - 1
while lo <= hi:
mid = (lo + hi) // 2. 1point3acres.com
if nums[mid] == target:
return mid
elif nums[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return -1进阶:当题目问"最小的可行值 / 最大的满足条件的 x",且答案单调时,用二分答案——不是在数组上二分,而是在答案的取值范围上二分,配一个判定函数。看到经常就是它。 5. BFS(无权图最短步数 / 层序)
from collections import deque
def bfs(start, target):
q = deque([start])-baidu 1point3acres
visited = {start}
steps = 0
while q:
for _ in range(len(q)): # 一次处理一整层
node = q.popleft()
if node == target:
return steps
for nxt in neighbors(node):
if nxt not in visited:
visited.add(nxt)
q.append(nxt)
steps += 1.google и
return -1
6. DFS / 回溯(所有组合 / 排列 / 子集)
def backtrack(path, choices, res):
if is_complete(path):
res.append(path[:]) # 存副本,不是引用
return
for i, choice in enumerate(choices):. 1point 3 acres
path.append(choice) # 做选择
backtrack(path, next_choices(choices, i), res)
path.pop() # 撤销选择回溯三要素:路径(已选)、选择列表(可选)、结束条件。 7. 动态规划(五步定式)
DP 不要背题,要背推导流程:
- 定义状态:或代表什么?
- 状态转移方程:由哪些更小的状态推出?
- 初始化:base case 是什么?
- 遍历顺序:从小到大 / 从后往前 / 二维的行列顺序。
- 返回值:答案是还是?
# 例:爬楼梯 / 打家劫舍类
def rob(nums):
prev, cur = 0, 0
for x in nums:. .и
prev, cur = cur, max(cur, prev + x) # 状态转移
return cur
8. 单调栈(下一个更大元素)
def next_greater(nums):. From 1point 3acres bbs
res = [-1] * len(nums)
stack = [] # 存下标,栈内单调递减
for i, x in enumerate(nums):
while stack and nums[stack[-1]] < x:
res[stack.pop()] = x
stack.append(i)
return res
9. 堆 / Top K(维护大小为 k 的堆). 1point 3 acres
import heapq. 1point3acres.com
def top_k(nums, k):. .и
heap = [] # 最小堆
for x in nums:. 1point3acres.com
heapq.heappush(heap, x). .и
if len(heap) > k:
heapq.heappop(heap) # 弹掉最小的,堆里始终是最大的 k 个. From 1point 3acres bbs
return heap
10. 并查集(动态连通性)
class UnionFind:
def __init__(self, n):. 1point3acres.com
self.parent = list(range(n))
self.rank = [0] * n
def find(self, x):
while self.parent[x] != x:
self.parent[x] = self.parent[self.parent[x]] # 路径压缩. .и
x = self.parent[x]
return x
def union(self, a, b):
ra, rb = self.find(a), self.find(b)
if ra == rb:
return False
if self.rank[ra] < self.rank[rb]:
ra, rb = rb, ra
. Waral dи, self.parent[rb] = ra
if self.rank[ra] == self.rank[rb]:
self.rank[ra] += 1. 1point3acres.com
return True. 1point3acres
. check 1point3acres for more.
完整示范:用框架解一道题
题目:给定字符串,求不含重复字符的最长子串的长度。(LC 3)
第 1 步 · 读题:输入字符串,输出一个整数(长度)。边界:空串返回 0,全相同字符返回 1。约束→ 目标。
第 2 步 · 定模式:关键词是"连续子串 + 最长" → 速查表 B 直接命中滑动窗口。
第 3 步 · 思路:暴力解是枚举所有子串再判重,甚至,在下会超时。滑动窗口:右指针扩张,遇到重复字符时收缩左指针,用一个集合/哈希记录窗口内字符。. Χ
第 4 步 · 编码:.1point3acres
def length_of_longest_substring(s):
seen = set()
left = 0. From 1point 3acres bbs
res = 0
for right, c in enumerate(s):. 1point 3 acres
while c in seen: # 出现重复,收缩左边界
seen.remove(s[left])
left += 1. Waral dи,
seen.add(c)
res = max(res, right - left + 1)
return res
第 5 步 · 验证:→ 3();→ 0;→ 1。复杂度:每个字符最多进出窗口一次,时间,空间。✅ 符合目标。
整套流程走下来,没有一步是"灵光一现",全是可复现的动作。
卡住了怎么办:解题急救清单. Χ
写题时卡住是常态。按顺序试这几招:
- 回到暴力解——先能跑通,再谈优化。有暴力解总比交白卷强。
- 换个数据结构——"我在反复查找?" → 哈希表;"我要频繁取最值?" → 堆;"我在维护有序?" → 有序结构 / 二分。
- 正难则反——正着推不动,试试从结果倒推、从后往前遍历、或求补集。
- 画图 / 举更大的例子——很多规律要在的例子上才看得出来。
- 找不变量——双指针、单调栈的本质都是"维护某个不变量"。问自己"循环里什么东西始终成立?"
- 拆成子问题——能不能分治?能不能先排序把问题简化?
如何练习:让框架变成本能
- 按模式刷,别随机刷:一次集中攻一个模式(比如连做 10 道滑动窗口),比东一榔头西一棒子有效得多——你要的是"看到信号就条件反射"。
- 刷完必总结:每道题记一句话——"这题的信号是 X,所以用模式 Y"。这句话比完整题解更值钱。
- 间隔重复:把"信号 → 模式"的映射和模板做成卡片,用间隔重复复习。模式模板就该像九九乘法表一样是肌肉记忆。
- 限时 + 讲出来:模拟面试环境,边写边讲。能把思路讲清楚,比自己闷头写对更重要。
- 回顾错题:错过的题两周后重做。如果还是卡在同一步,说明那个模式没真正吃透。
一句话总结读题定复杂度 → 信号定模式 → 暴力打底 → 套模板 → dry run 验证。 把每道题都塞进这条流水线,"没见过的题"会越来越少,因为你处理的从来不是"题",而是"模式"。 |