1. 动态规划专题精讲
今天咱们来啃动态规划领域的几块硬骨头——子序列相关的高频面试题。这些题目在各大厂的算法面试中出场率极高,但很多同学面对这类问题时总感觉无从下手。我将结合自己刷题和面试官的经验,带大家用动态规划的视角重新审视这些经典问题。
动态规划解题的核心在于状态定义和转移方程,而字符串问题往往需要二维DP数组来表示子问题的解。
1.1 题目概览与解题思路
我们先快速过一遍三个题目的基本要求:
-
115.不同的子序列:给定字符串s和t,计算s的子序列中等于t的个数。例如s="rabbbit",t="rabbit",返回3。
-
583. 两个字符串的删除操作:给定两个单词word1和word2,返回使word1和word2相同所需的最小删除次数。例如word1="sea",word2="eat",返回2。
-
72. 编辑距离:给定两个单词word1和word2,计算将word1转换成word2所需的最少操作次数(插入、删除、替换)。例如word1="horse",word2="ros",返回3。
虽然题目表述各异,但它们的核心都是字符串匹配与编辑问题。解决这类问题的通用思路是:
- 定义dp数组的含义(通常为二维)
- 确定base case(初始条件)
- 找出状态转移方程
- 确定遍历顺序
- 举例推导验证
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 不同的子序列问题解析
2.1 问题重述与示例分析
题目要求计算字符串s中等于t的子序列数量。子序列的定义是:不改变字符相对顺序的情况下删除某些字符得到的新字符串。
以示例s="rabbbit",t="rabbit"为例:
- 删除s[3]得到"rabbit"
- 删除s[4]得到"rabbit"
- 删除s[5]得到"rabbit"
因此返回3。
2.2 DP数组定义与初始化
我们定义dp[i][j]表示s[0..i-1]的子序列中等于t[0..j-1]的个数。这样定义可以方便处理空字符串的情况。
初始化条件:
- dp[i][0] = 1:空字符串是任何字符串的子序列
- dp[0][j] = 0 (j>0):非空字符串不可能是空字符串的子序列
2.3 状态转移方程推导
考虑s[i-1]和t[j-1]的关系:
- 当s[i-1] == t[j-1]时:
- 可以选择使用s[i-1]匹配t[j-1],此时数量为dp[i-1][j-1]
- 也可以选择不使用s[i-1]匹配t[j-1],此时数量为dp[i-1][j]
- 因此dp[i][j] = dp[i-1][j-1] + dp[i-1][j]
- 当s[i-1] != t[j-1]时:
- 只能选择不使用s[i-1],因此dp[i
