给定一个字符串 s
和一个字符串 t
,计算在 s
的子序列中 t
出现的个数。
字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE"
是 "ABCDE"
的一个子序列,而 "AEC"
不是)
题目数据保证答案符合 32 位带符号整数范围。
示例 1:
输入:s = "rabbbit", t = "rabbit" 输入:3
解析:
重点在这个 “选”,s 串有哪些选择,做出不同的选择会带来什么状态。
s = babgbag,t = bag为例,末尾字符相同,于是 s 有两种选择:用s[s.length-1]去匹配掉t[t.length-1],问题规模缩小:继续考察babgba和ba
不这么做,但t[t.length-1]需要被匹配,则在babgba中找匹配,考察babgba和bag
dp[i][j]:以i为结尾的s子序列中出现以j−1为结尾的t的个数dp[i][j]
当s[i]和t[j]相等时,一共就只有两种选择,一种是s[i]和t[j]进行匹配,另外一种是s[i]和t[j]不匹配,这两种情况相加就是全集。
不让 s[i] 参与匹配,也就是需要让 s 中 [0,i-1][个字符去匹配 t 中的[0,j] 字符。此时匹配值为 dp[i−1][j]
让 s[i] 参与匹配,这时候只需要让 s 中 [0,i−1] 个字符去匹配 t 中的[0,j−1] 字符即可,同时满足 s[i]==t[j]。此时匹配值为 dp[i−1][j−1]
所以dp状态方程如下:
s[i]==t[j],dp[i][j] = dp[i-1][j-1]+dp[i-1][j]
s[i]!=t[j],dp[i][j] = dp[i-1][j];
dp初始化
dp[i][0]:t为空串,此时 s 为了匹配它,方式只有1种:删光自己所有的字符,变成空串。(或 s 也是空串,什么都不做就匹配了,方式数也是1)
因此dp[i][0]都是1。
dp[0][j]:s 为空串,但 t 不是,s 怎么样也匹配不了 t,方式数为 0
因此dp[0][j]都是0。
class Solution {
public int numDistinct(String s, String t) {
int n = s.length();
int m = t.length();
int [][] dp = new int[n+1][m+1];
for(int i=0;i<n+1;i++){
dp[i][0]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s.charAt(i-1) == t.charAt(j-1)){
dp[i][j] = dp[i-1][j-1]+dp[i-1][j];
}
else{
dp[i][j] = dp[i-1][j];
}
}
}
return dp[n][m];
}
}