题目:
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中的子串,而且相对位置顺序要跟T一致。
因此,我们建立矩阵,依次标明S和T的匹配情况。以题目中 的例子来看:
初始矩阵为:
r | a | b | b | b | i | t | |
r | |||||||
a | |||||||
b | |||||||
b | |||||||
i | |||||||
t |
再次,对于T的某一个字母x,如果S中有多个x可以匹配,必然是先跟S前面的x相匹配,那么,该矩阵的列的计算顺序也就是从前往后。
现在思考矩阵(设为W)值的意义:
不妨设当前位置为W[i][j],即t[i] 要跟S[j]相匹配,则有两种情况:
1.T[i] !=S[j];表示目前为止匹配到T[i]时的情况总数,其结果为上一层的结果,那么当前是W[i][j],在利用上一层的结果时,最好利用W[i-1][j-1]来记录。
2.T[i]==S[j];表示当前位置匹配到T[i]时的情况总数,其结果为上一层的结果数*1(1 为当前T[i]=S[j]这个情况)+ 当前层T[i]跟S[j]之前匹配到的情况总数。
因此,对于情况2来说,在每一层都需要初始化一个sum变量,记录截止到T[i]跟S[j]进行匹配之前的总的结果数,然后更新sum,并赋值给W[i][j]。
对于1的情况而言,每次将sum值直接赋给W[i][j]就好了。
这种处理方法的巧妙地方就在于:
对于W[i][j]而言,在对应的两个字母匹配之前的字母匹配情况都可以直接由W[i-1][j-1]得出从而直接算出当前两个字母匹配(或不匹配)之后的结果,
作为后面字母的“垫脚石”。
更具体的谈:上述矩阵计算步骤为:从上到下,从左到右。
r | a | b | b | b | i | t | |
r | sum=0->sum+1-> (sum=1) | sum=1->1-> (sum=1) | sum=1->1-> (sum=1) | sum=1->1-> (sum=1) | sum=1->1-> (sum=1) | sum=1->1-> (sum=1) | sum=1->1-> (sum=1) |
a | sum=1->0-> (sum=1) | sum=0->1*1 (sum=1) | sum=1->1 (sum=1) | sum=1->1 (sum=1) | sum=1->1 (sum=1) | sum=1->1 (sum=1) | sum=1->1 (sum=1) |
b | sum=0->0 (sum=0) | sum=0->0 (sum=0) | sum=0->1*1 (sum=1) | sum=1-> sum+1*1 (sum=2) | sum=2-> sum+1*1 (sum=3) | sum=3-> 3 (sum=3) | sum=3-> 3 (sum=3) |
b | 0 | 0 | 0+0*1=0 | 0+1*1=1 | 1+2*1=3 | 3 | 3 |
i | 0 | 0 | 0 | 0 | 0 | 0+3*1=3 | 3 |
t | 0 | 0 | 0 | 0 | 0 | 0 | 0+3*1=3 |
最终在W[5][6]得到答案。
AC代码:
public class Distinct_Subsequences {
public int numDistinct(String S, String T) {
if(S.length()==0 && T.length()==0)
return 1;
if(S.length()==0 || T.length()==0)
return 0;
char[] s = S.toCharArray();
char[] t = T.toCharArray();
int[][] w = new int[t.length][s.length];
int sum = 0;
for(int i=0;i<s.length;i++){
if(t[0]==s[i]){
sum++;
w[0][i] = sum;
} else
w[0][i] = sum;
}
for(int i=1;i<t.length;i++)
w[i][0]=0;
for(int i=1;i<t.length;i++){
sum=0;
for(int j=1;j<s.length;j++){
if(t[i]==s[j]){
sum+=w[i-1][j-1];
w[i][j] = sum;
}
else
w[i][j]=sum;
}
}
return w[t.length-1][s.length-1];
}
public static void main(String[] args){
Distinct_Subsequences distinct_subsequences = new Distinct_Subsequences();
System.out.println(distinct_subsequences.numDistinct("r",""));
}
}