描述
给出字符串S和字符串T,计算S的不同的子序列中T出现的个数。
子序列字符串是原始字符串通过删除一些(或零个)产生的一个新的字符串,并且对剩下的字符的相对位置没有影响。(比如,“ACE”是“ABCDE”的子序列字符串,而“AEC”不是)。
样例
给出S = "rabbbit", T = "rabbit"
返回 3
思路:
动态规划问题,一开始没有想出思路,
看了: http://www.cnblogs.com/yuzhangcmu/p/4196373.html
https://blog.csdn.net/fightforyourdream/article/details/17346385?reload#comments
这道题可以作为两个字符串DP的典型:
两个字符串:
先创建二维数组存放答案,如解法数量。注意二维数组的长度要比原来字符串长度+1,因为要考虑第一个位置是空字符串。
然后考虑dp[i][j]和dp[i-1][j],dp[i][j-1],dp[i-1][j-1]的关系,如何通过判断S.charAt(i)和T.charAt(j)的是否相等来看看如果移除了最后两个字符,能不能把问题转化到子问题。
最后问题的答案就是dp[S.length()][T.length()]
就以例子来讲,可以画出如下的状态矩阵,如果T[i]==S[j], dp[i][j] = dp[i][j-1] + dp[i-1][j-1] , 否则, dp[i][j] = dp[i][j-1]。
这里的 dp 是以 T.length() 为 行数, 以 S.length() 为 列数的。
public static int numDistinct(String S, String T) {
// write your code here
int[][] dp = new int[T.length()+1][S.length()+1];
for (int i = 0; i <= S.length(); i++) {
dp[0][i] = 1;
}
for (int i = 1; i <= T.length(); i++) {
dp[i][0] = 0;
}
for (int i = 1; i <= T.length(); i++) {
for (int j = 1; j <= S.length(); j++) {
dp[i][j] = dp[i][j-1] + (T.charAt(i-1) == S.charAt(j-1)?dp[i-1][j-1]:0);
}
}
for (int i = 0; i <= T.length(); i++) {
for (int j = 0; j <= S.length(); j++) {
System.out.print(dp[i][j]+ " ");
}
System.out.println();
}
return dp[T.length()][S.length()];
}
递归的解法,没有细看:
public int numDistinct(String S, String T) {
// Start typing your Java solution below
// DO NOT write main() function
if (S.length() == 0) {
return T.length() == 0 ? 1 : 0;
}
if (T.length() == 0) {
return 1;
}
int cnt = 0;
for (int i = 0; i < S.length(); i++) {
if (S.charAt(i) == T.charAt(0)) {
cnt += numDistinct(S.substring(i + 1), T.substring(1));
}
}
return cnt;
}