给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。
一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE"
是 "ABCDE"
的一个子序列,而 "AEC"
不是)
示例 1:
输入: S ="rabbbit"
, T ="rabbit" 输出: 3
解释: 如下图所示, 有 3 种可以从 S 中得到"rabbit" 的方案
。 (上箭头符号 ^ 表示选取的字母)rabbbit
^^^^ ^^rabbbit
^^ ^^^^rabbbit
^^^ ^^^ 示例 2: 输入: S ="babgbag"
, T ="bag" 输出: 5
解释: 如下图所示, 有 5 种可以从 S 中得到"bag" 的方案
。 (上箭头符号 ^ 表示选取的字母)babgbag
^^ ^babgbag
^^ ^babgbag
^ ^^babgbag
^ ^^babgbag
^^^
这是一道比较难的动态规化题目,令状态dp[i][j] s的前i个子序列中T的前j个字串出现的次数,这里字母的下标从1开始,
可以得出边界条件是dp[i][0] = 1, 通过全部删除得到匹配。
很容易找到状态方程 dp[i][j] = dp[i-1][j] + (dp[i-1][j-1] if s[i] == t[i]) 代码
class Solution {
public:
long numDistinct(string s, string t) {
int n=s.size();
int m=t.size();
vector<vector<long>> dp(n+1,vector<long>(m+1,0));
// 字母从1开始
// dp[i][j] // 表示第个i结尾的子序列中前j个字符T出现的次数
// dp[i][j] = dp[i-1][j]
// dp[i][j] = dp[i-1][j-1] if(S[i]==T[j])
for(int i=0;i<=n;i++){
dp[i][0] = 1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
dp[i][j] = dp[i-1][j];
if(s[i-1]==t[j-1])
dp[i][j]+=dp[i-1][j-1];
}
}
return dp[n][m];
}
};