题目描述
思路解析动画文字版
关键不是背模板,而是看懂为什么这题适合二维 DP。
① 基底 dp[0][0]=true:空串匹配空模式:空串和空模式一定匹配 → dp[0][0]=true,整张表从这里出发。
② x* 可匹配空串(第 0 行):c* 可以匹配「0 个 c」→ 跳过 c*,dp[0][2] 继承 dp[0][0]=1;同理 a* 让 dp[0][4] 继承 dp[0][2]=1。
③ 普通字符(或 .)相等 → 继承左上:s 的 'a' 与 p 的 'a' 相等(若 p 是 '.' 也算匹配)→ 这格继承左上 dp[0][2]=1。
④ 遇到 *,先试「匹配 0 次」→ 看左 2 列:遇到 c*,先考虑「一个 c 都不要」→ 跳过 c* 这两位,看 dp[1][0]=0 → 这格为 0。
⑤ * 匹配多次:前字符能吃当前 → 看上一行:a* 且 'a' 能吃掉 s 的 'a' → 复用「吃掉这个 a 之前」的结果 dp[0][4]=1 → 这格为 1。
⑥ a* 继续再吃一个 a:a* 再吃 s 的第二个 a → dp[2][4] 看上一行 dp[1][4]=1 → 仍为 1。
⑦ 结尾 b 相等 → 继承左上:s 的 'b' 与 p 的 'b' 相等 → dp[3][5] 继承左上 dp[2][4]=1。
⑧ 答案在右下角 dp[m][n]:右下角 dp[3][5]=1 → "aab" 匹配 "c*a*b",返回 true。
把这句话记住,下次遇到同类题,就能更快选出方向。
迁移阶梯:把这题练到能复述后,再去同类题里迁移:先复用状态定义,再调整边界条件。
边界三连:边界三连:极端输入先过一遍。
几个高频追问,记住答法。
参考代码
class Solution: def isMatch(self, s, p): m, n = len(s), len(p) dp = [[False]*(n+1) for _ in range(m+1)] dp[0][0] = True for j in range(2, n+1): if p[j-1] == '*': dp[0][j] = dp[0][j-2] for i in range(1, m+1): for j in range(1, n+1): if p[j-1] in {s[i-1], '.'}: dp[i][j] = dp[i-1][j-1] elif p[j-1] == '*': dp[i][j] = dp[i][j-2] if p[j-2] in {s[i-1], '.'}: dp[i][j] = dp[i][j] or dp[i-1][j] return dp[m][n]复杂度
- 时间复杂度:O(mn),填 (m+1)×(n+1) 张表,每格 O(1)
- 空间复杂度:O(mn),dp 表 (m+1)×(n+1),可滚动到 O(n)
可套用的代码模板
模板不是死背,而是提醒你写代码前先把状态、转移和边界排好。
# 二维 DP 通用检查表# 1. 定义状态/指针/容器# 2. 每轮只做一个清晰动作# 3. 更新答案并处理边界易错点
面试追问把动画讲成自己的话
追问为什么 '*' 是难点?
追问'.' 和 '*' 怎么配合?
追问复杂度?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
最大正方形
LeetCode 221 · 中等 · 沿着 二维动态规划 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题