Given a string S and a string T, count the number of distinct subsequences of T in S.
A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE"
is a subsequence of "ABCDE"
while "AEC"
is not).
Here is an example:
S = "rabbbit"
, T = "rabbit"
Return 3
.
问题:给定字符串 S, T, 求 T 在 S 中有多少个不同的子序列。
一开始看到这道题,没有思路,在网上看了别人的解答才了解到如何解题。这是一道 dp 题,如果能想得到状态转义 关系,答案就比较明显了。解法有点想 背包问题的解法。
二维数组 vv[T.len][S.len] 存储中间结果。 vv[i][k], 表示 T[0, i] 在 S[0, k] 中的不同的子序列个数。
状态转换关系,文字描述:
当 S[i] 和 T[k] 不相等时, T[0, i] 在 S[0, k] 的不同子序列个数,和在S[0, k-1] 的不同子序列个数相同。
当 S[i] 和 T[k] 相同时, T[0, i] 在 S[0, k] 的不同子序列个数等于 S[i] 被采取的情况( vv[i-1][k-1] ), 加上 S[i] 不被采取的情况 ( vv[i][k-1] )。
状态转换关系,公式表示:
当 S[i] != T[k] 时,vv[i][k] = vv[i][k-1]
当 S[i] == T[k] 时,vv[i][k] = vv[i-1][k-1] + vv[i][k-1]
1 int numDistinct(string s, string t) { 2 3 if (t.size() > s.size()) { 4 return 0; 5 } 6 7 vector<vector<int>> vv(t.size(), vector<int>(s.size(), -1)); 8 9 // 边界值处理 10 for (int i = 1; i < vv.size(); i++) { 11 vv[i][i-1] = 0; 12 } 13 14 // 边界值处理 15 if (s[0] == t[0]) { 16 vv[0][0] = 1; 17 }else{ 18 vv[0][0] = 0; 19 } 20 21 // 边界值处理 22 for (int i = 1; i < vv[0].size(); i++) { 23 if (t[0] == s[i]) { 24 vv[0][i] = vv[0][i-1] + 1; 25 }else{ 26 vv[0][i] = vv[0][i-1]; 27 } 28 } 29 30 // 状态转移 31 for (int i = 1 ; i < vv.size(); i++) { 32 for (int k = i ; k < vv[i].size(); k++) { 33 if (t[i] != s[k]) { 34 vv[i][k] = vv[i][k-1]; 35 }else{ 36 vv[i][k] = vv[i-1][k-1] + vv[i][k-1]; 37 } 38 } 39 } 40 41 return vv[t.size()-1][s.size()-1]; 42 }