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
.
题意:给定2个字符串S和T。将字符串S删除若干个字符之后(可以为0个)得到字符串T,请问共有多少种删除方式?
这个题的第一想法是使用递归,事实上也是最容易想到的解题方法,下面介绍递归解法以及将其转化成动态规划的解法。
1、递归解法(此方法在LeetCode上运行会超时,仅作为参考以及第二解法的过渡)
核心思想:遍历字符串S的每个字符,当S中某个字符与字符串T的首字符相同时,递归调用方法numDistinct(s.substring(k),t.substring(1)),其中k表示S中下标为k 的字符与字符串T的首字符相同,最后将每次递归调用返回的值相加,就得到最终结果。
下面贴代码:
public class Solution {
public int numDistinct(String s, String t) {
if(s.length()<t.length()) return 0;
if(s.length()==t.length()){
if(s.equals(t)) return 1;
else return 0;
}
if(t.equals("")) return 1;
int num = 0;
for(int i=0;i<=s.length()-t.length();i++){
if(s.charAt(i) == t.charAt(0))
num += numDistinct(s.substring(i+1),t.substring(1));
}
return num;
}
}
2、
动态规划解法
我们定义一个数组a[s.length+1][t.length+1]
其中a[i][j]表示:
s1:字符串S从下标为i开始到末尾的子串;
t1:字符串T从下标为j开始到末尾的子串;
a[i][j]表示字符串s1删除若干字符后得到t1总共有多少种删除方式。
那么a[0][0]即是题目要求的结果。
仔细观察我们可以看到这样一个规律,对于每一个a[i][j],有以下2种情况:
1.如果S下标为i的字符等于T下标为j的字符,那么a[i][j] = a[i+1][j+1] + a[i+1][j];
2.如果S下标为i的字符不等于T下标为j的字符,那么a[i][j] = a[i+1][j];
有了以上推倒规律之后,我们再来考虑初始条件,事实上初始条件即为0
下面是动态规划解法的代码:
public class Solution {
public int numDistinct(String s, String t) {
if(s.length()<t.length()) return 0;
if(s.length()==t.length()){
if(s.equals(t)) return 1;
else return 0;
}
if(t.equals("")) return 1;
int[][] a = new int[s.length()+1][t.length()+1];
a[s.length()][t.length()-1] = 0;
for(int i=s.length()-1;i>=0;i--){
if(s.charAt(i)==t.charAt(t.length()-1))
a[i][t.length()-1]=a[i+1][t.length()-1]+1;
else a[i][t.length()-1]=a[i+1][t.length()-1];
}
for(int j=t.length()-2;j>=0;j--){
for(int i=s.length()+j-t.length();i>=0;i--){
if(s.charAt(i)==t.charAt(j)){
a[i][j] = a[i+1][j+1] + a[i+1][j];
}else{
a[i][j] = a[i+1][j];
}
}
}
return a[0][0];
}
}
此类题目用动态规划解决是一种很好的方法,但是状态转移方程不易寻找,我们可以从递归解法中寻找规律,找到 状态转移方程