Distinct Subsequences
题目: 给定两个string \(S\)、\(T\),计算序列为\(T\)的\(S\)的子序列的数量。
例如S = "rabbbit", T = "rabbit",返回结果为3
子序列:例如,"ACE"是"ABCDE"的子序列。
这里我用动态规划的来求解
- 构建DP表,大小为 \(T.size + 1\)行,\(S.size + 1\)列
+1是为了后面查表方便。 - 第一次,填表:判断T[j] 是否 等于 S[i] 。1代表相同,0代表不同
- 第二次,查表:从T[1]到T[end] 有几种走法
走法:从1到1,走也是有条件的,只能走自己的斜下方的方向,不能垂直向下,向右走
有几种走法即有几个子序列
计算有几种走法可以用递归,但效率较低,可用循环。
![](//images0.cnblogs.com/blog/661985/201502/152113244487788.png)
代码中的查表为从后向前
下面为C++代码
int numDistinct(string S, string T) {
int num_T = T.size(), num_S = S.size();
if (num_S < num_T) return 0;
vector<vector<int>> DP(num_T + 1, vector<int>(num_S + 1, 0)); //初始化DP表,全为0
for (int i = 0; i < num_S; ++i){ // DP表第一行为1,最后一个为0
DP[0][i] = 1;
}
// DP 填表
for (int j = 1; j < num_T + 1; ++j){
for (int i = j; i < num_S + 1; ++i){
if (T[j - 1] == S[i - 1]){
DP[j][i] = 1;
}
}
}
// 查表,计算得到结果
for (int j = num_T; j > 0; --j){
int nn = 0;
for (int i = num_S - (num_T - j); i > 0; --i){
nn += DP[j][i];
if (DP[j - 1][i - 1] >= 1){
DP[j - 1][i - 1] = nn;
}
}
}
return DP[0][0];
}
时间复杂度 \(O(n*m)\)
空间\(O(n*m)\)