1. 动态规划专题精讲
这三个题目都是经典的字符串动态规划问题,它们代表了动态规划在字符串处理中的典型应用场景。作为算法训练营的进阶内容,这些题目考察的是对动态规划思想的深入理解和灵活运用能力。
我在刷题和面试辅导过程中发现,很多同学对这类字符串DP问题存在畏难心理。实际上只要掌握正确的分析方法和解题模板,这类问题都有清晰的解决路径。今天我们就来彻底攻克这三个经典问题,建立完整的解题思维框架。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 115.不同的子序列
2.1 问题重述与分析
给定字符串s和t,计算s的子序列中等于t的个数。子序列是指通过删除某些字符而不改变剩余字符相对位置形成的新字符串。
例如:
s = "rabbbit", t = "rabbit"
输出:3
解释:
有3种可以从s中得到"rabbit"的方案
这个问题的难点在于如何避免重复计算,同时正确处理字符匹配和不匹配的情况。我们需要设计一个状态转移方程来系统性地计算所有可能性。
2.2 DP状态定义
定义dp[i][j]表示s的前i个字符中,t的前j个字符出现的次数。我们的目标是求dp[len(s)][len(t)]。
初始化条件:
- dp[i][0] = 1 (空串是任何字符串的子序列)
- dp[0][j] = 0 (j>0时,空串无法组成非空串)
2.3 状态转移方程
当s[i-1] == t[j-1]时:
dp[i][j] = dp[i-1][j-1] + dp[i-1][j]
(匹配当前字符的情况 + 不匹配当前字符的情况)
当s[i-1] != t[j-1]时:
dp[i][j] = dp[i-1][j]
(只能不匹配当前字符)
2.4 代码实现
python复制def numDistinct(s: str, t: str) -> int:
m, n = len(s), len(t)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(m + 1):
dp[i][0] = 1
for i in range(1, m + 1):
for j in range(1, n + 1):
