Distinct Subsequences
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
.
思路: 如果简单的想可以用DFS,从S中顺序找到sizeof(T)个字符,等于T即可,输出可能性,复杂度为O(2^n)
所以考虑用动态规划求解,我们可以假设flag[i][j]表示S的前i个字符和T的前j个字符中满足条件的个数;
即S中前i个字符中顺序挑选j个字符来构成T中前j个字符
flag[0][0] = 1;
flag[i][0] i>0 = 1
flag[0][i] i>0 = 0
flag[i][j] 与 flag[i-1][j] flag[i][j-1] 还有flag[i-1][j-1]满足什么关系呢?
假设T遍历到了第j个字符,而S遍历到了第i个字符,前面已经得到了flag[i-1][j] flag[i-1][j-1] flag[i-1][j-1],我们需要思考S中增加第i个字符对结果会造成哪些影响?
思考第i个字符S(i-1) 和 第j个字符T(j-1)关系? 如果不相等,则第i个字符无关紧要,不会对结果造成影响,对subsequence没有影响;
则flag[i][j] = flag[i-1][j]
如果相等呢?这就会对结果有影响,该字符可以作为subsequence的最后一个字符
如果是,则已经挑选出一个,则剩余的i-1个字符为flag[i-1][j-1]
如果不是,则该字符无效,则剩余的i-1个字符中挑选j个字符,为flag[i-1][j]
则总共 flag[i-1][[j-1] + flag[i-1][j]
java代码:
- public int numDistinct(String S, String T) {
- int s1 = S.length();
- int t1 = T.length();
- if(s1<t1) return 0;
- int[][] flag = new int[s1+1][t1+1];
- flag[0][0] = 1;
- for(int i=1;i<=t1;i++)
- flag[0][i] = 0;
- for(int i=1;i<=s1;i++) {
- flag[i][0] = 1;
- }
- for(int i=1;i<=s1;i++) {
- for(int j=1;j<=i && j<=t1;j++) {
- flag[i][j] = flag[i-1][j];
- if(S.charAt(i-1)==T.charAt(j-1)) {
- flag[i][j] += flag[i-1][j-1];
- }
- }
- }
- return flag[s1][t1];
- }
参考:http://blog.csdn.net/abcbc/article/details/8978146
遇到这种两个串的问题,很容易想到DP。但是这道题的递推关系不明显。可以先尝试做一个二维的表int[][] dp,用来记录匹配子序列的个数(以S ="rabbbit"
,T = "rabbit"
为例):
r a b b b i t
1 1 1 1 1 1 1 1
r 0 1 1 1 1 1 1 1
a 0 0 1 1 1 1 1 1
b 0 0 0 1 2 3 3 3
b 0 0 0 0 1 3 3 3
i 0 0 0 0 0 0 3 3
t 0 0 0 0 0 0 0 3
从这个表可以看出,无论T的字符与S的字符是否匹配,dp[i][j] = dp[i][j - 1].就是说,假设S已经匹配了j - 1个字符,得到匹配个数为dp[i][j - 1].现在无论S[j]是不是和T[i]匹配,匹配的个数至少是dp[i][j - 1]。除此之外,当S[j]和T[i]相等时,我们可以让S[j]和T[i]匹配,然后让S[j - 1]和T[i - 1]去匹配。所以递推关系为:
dp[0][0] = 1; // T和S都是空串.
dp[0][1 ... S.length() - 1] = 1; // T是空串,S只有一种子序列匹配。
dp[1 ... T.length() - 1][0] = 0; // S是空串,T不是空串,S没有子序列匹配。
dp[i][j] = dp[i][j - 1] + (T[i - 1] == S[j - 1] ? dp[i - 1][j - 1] : 0).1 <= i <= T.length(), 1 <= j <= S.length()