AlgoMooc
图解算法

算法心法 · 从题目到模型

别把每道题都当新题。先把题目翻译成模型。

真正让人进步的不是刷题数量,而是看到一道题时,能判断它属于哪类问题、该用哪套骨架、哪里容易错。这个模块把高频算法收敛成六套可迁移的心法:先看懂,再会写,最后能讲给面试官听。

6

套核心模型覆盖常见题型

252

道动画题解可跟着练

3

步训练,从识别到迁移

题目变模型
模型变模板

识别信号

有序、区间、选或不选

套入骨架

指针、递归、DP 表

动画推演

看清状态变化

复述迁移

换题也能讲清

适合谁

不同阶段,从这里拿到不同价值

同一套心法,不是只给面试党背模板。它要同时解决看不懂、刷不动、讲不清和迁移不了四类问题。

BEGINNER

初学者,先建立题型感觉

不用一上来背复杂模板。先知道这道题为什么会想到双指针、DP、栈,再跟着动画走一遍。

  • 看每套心法的识别信号
  • 点配套简单题,先看动画
  • 把题意复述成输入、输出和限制条件

CAMPUS

校招准备,把刷题变成专题训练

最怕东刷一道、西刷一道。这里把常见题收成专题,帮你从会一道变成会一类。

  • 按学习路径刷高频题
  • 每题复盘识别信号、模板、易错点
  • 面试前练 30 秒标准回答

ADVANCED

进阶学习,补证明、复杂度和迁移

只会写代码还不够,高阶题更看重抽象能力:为什么正确,复杂度如何,能不能换场景复用。

  • 关注不变量、递推定义和边界证明
  • 把同一模型迁移到图、字符串、区间
  • 用相邻题检测自己是不是真的会了

学习闭环

从看懂,到会写,再到能迁移

01

看题目信号

先判断题里出现的是有序、连续区间、选或不选、最近未处理,还是树的子问题。

02

套解题骨架

把题翻译成双指针、DP、回溯、树形递归、二分或栈,再写出最小可用模板。

03

动画验证和迁移

用动画检查状态变化和边界条件,再换一两道同类题验证迁移能力。

六套核心心法

每套都按识别信号、思考骨架、常见坑、配套题组织

先建立模型,再回到题库练。越是高频的题型,越值得把这套顺序练熟。

01

双指针

省掉一层循环

看相关题

看到数组、字符串、链表里出现成对比较、连续区间、原地处理,优先想双指针。它的价值是把暴力枚举的两层循环,压成一趟可控移动。

识别信号

有序数组找一对;最长或最短连续子串;链表中点、环;原地删除或移动元素。

常见坑

窗口题忘记维护计数;对撞题没利用有序性;快慢指针忘记处理偶数长度。

# 对撞指针:有序数组里找一对
l, r = 0, n - 1
while l < r:
    if 满足(l, r): return ...
    elif 偏大: r -= 1
    else: l += 1

先别背四种写法,记住指针移动必须排除一批不可能答案。每移动一步,都要能说清楚为什么那部分不用再看。

02

动态规划

定义状态,再谈转移

看相关题

DP 不是背公式,而是把一个大问题拆成一组更小的状态。只要状态定义清楚,转移方程通常会从最后一步怎么来里自然出现。

识别信号

求最优值、方案数、可不可行;有重复子问题;当前选择会影响后续。

常见坑

dp[i] 没定义清楚就写公式;初始化缺边界;背包遍历方向写反。

# DP 五问:每次都按这个顺序想
状态是什么?
从哪些更小状态转移?
初始值是什么?
按什么顺序填表?
能否压缩空间?

每做完一道 DP,把状态定义和转移来源写成一句话。面试官真正想听的不是代码多熟,而是你为什么这样定义状态。

03

回溯

选,递归,撤销

看相关题

回溯就是在一棵决策树上搜索。要做的不是乱试,而是定义清楚每层在选什么、哪些选择合法、什么时候收集答案。

识别信号

枚举所有方案;组合、排列、子集;棋盘搜索;需要试错和撤销。

常见坑

组合和排列去重混淆;忘记撤销选择;保存答案时没复制 path。

path.append(选项)   # 做选择
backtrack(下一层)   # 继续搜
path.pop()         # 撤销选择

把回溯画成树。每一层代表一个决策位置,每条边代表一次选择。你能画出来,就能写出来。

04

树形递归

拿左右子树拼自己

看相关题

二叉树题的核心不是背遍历顺序,而是想清楚当前节点要向父节点返回什么。递归函数一旦定义准确,前中后序只是处理时机不同。

识别信号

树的深度、路径、对称、最近公共祖先、BST 合法性。

常见坑

返回给父节点的值和全局答案混在一起;空节点基准值设错。

def dfs(node):
    if not node: return 基准值
    L = dfs(node.left)
    R = dfs(node.right)
    return 合并(L, R, node)

很多树题可以看作结构归纳。先证明空树成立,再假设左右子树答案正确,最后证明合并后当前节点正确。

05

二分

凡单调,皆可砍半

看相关题

二分不只是数组里找数。只要答案区间具有单调性,就可以在答案上二分:速度、容量、天数、阈值,都能变成可判定问题。

识别信号

有序数组;找第一个满足条件的位置;最小化最大值;答案越大越容易满足。

常见坑

边界开闭混乱;mid 不推进导致死循环;判定函数的单调方向想反。

# 下界二分:找第一个满足 cond 的位置
l, r = 0, n
while l < r:
    m = (l + r) // 2
    if cond(m): r = m
    else: l = m + 1
return l

二分答案题要先写判定函数。给我一个 x,我能不能判断 x 行不行?能判断,再谈二分。

06

最近未处理的问题

看相关题

栈解决的是最近的、还没闭合的东西:括号、路径、表达式、下一个更大元素。单调栈尤其重要,它把很多看似要回头比较的题压成 O(n)。

识别信号

括号匹配;嵌套解码;路径回退;找右边第一个更大或更小。

常见坑

单调栈里该存下标却存值;弹栈时机不对;忘记处理栈里剩余元素。

# 单调栈:为每个元素找右边第一个更大的
stack = []
for i, x in enumerate(arr):
    while stack and x > arr[stack[-1]]:
        j = stack.pop()
        ans[j] = i - j
    stack.append(i)

单调栈的本质是不变量维护。栈内元素保持单调,每个元素最多入栈出栈一次,所以总复杂度是 O(n)。

下一步,不是再收藏一篇文章,而是开始练。

建议每学一套心法,就回到图解题库跟三道题:一道入门,一道标准题,一道变形题。看懂动画以后,关掉页面复述思路,再默写一次代码。