1. 动态规划解题方法论:从子序列计数到最优代价问题
动态规划(Dynamic Programming)是算法领域解决复杂问题的利器,尤其在处理字符串相关问题时展现出强大的威力。今天我将通过两道力扣经典题目(115.不同的子序列和712.两个字符串的最小ASCII删除和),带大家深入理解动态规划在字符串处理中的应用。
这两道题看似不同,实则都遵循动态规划的核心思想:定义状态、确定边界、推导转移方程。我们先从子序列计数问题入手,再探讨最优代价问题的解法,最后你会发现它们本质上是同一套方法论在不同场景下的灵活应用。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 子序列计数问题:115.不同的子序列
2.1 问题理解与状态定义
给定字符串s和t,我们需要计算s中出现t的不同子序列的数量。例如:
- s = "rabbbit", t = "rabbit" → 输出3
- s = "babgbag", t = "bag" → 输出5
这里的关键是理解"子序列"的定义:不改变字符相对顺序,通过删除某些字符得到的新字符串。注意与"子串"的区别,子串要求字符必须连续。
我们定义dp[i][j]表示:s从第i个字符开始的子串(s[i:])中,包含t从第j个字符开始的子串(t[j:])作为子序列的数量。这种从后往前的定义方式在字符串DP中很常见,能简化边界条件的处理。
2.2 边界条件与状态转移
边界条件是DP问题中容易被忽视但至关重要的部分:
- 当j = n(t遍历完):空字符串是任何字符串的子序列,因此dp[i][n] = 1
- 当i = m且j < n(s遍历完但t未完成):空字符串无法包含非空字符串,dp[m][j] = 0
状态转移方程需要考虑两种情况:
-
s[i] == t[j]时:
- 可以选择用s[i]匹配t[j],然后看dp[i+1][j+1]
- 也可以选择不用s[i]匹配t[j],看dp[i+1][j]
- 因此dp[i][j] = dp[i+1][j+1] + dp[i+1][j]
-
s[i] != t[j]时:
- 只能跳过s[i],看dp[i+1][j]
- 因此dp[i][j] = dp[i+1][j]
2.3 Java实现与优化技巧
java复制class Solution {
