/**
* @param {string} s
* @param {string} t
* @return {number}
*/
var numDistinct = function(s, t) {
//初始化dp数组
let dp=Array.from(Array(s.length+1),()=>Array(t.length+1).fill(0));
//当j=0时,相当于t是空字符串,空字符串在另一个字符串的子串中出现一次,此时第一列都初始化为1
for(let i=0;i<=s.length;i++){
dp[i][0]=1;
}
//当s[i-1]==t[j-1]:
//1、用s[i-1]来匹配==>dp[i][j]=dp[i-1][j-1]
//2、不用s[i-1]来匹配==>dp[i][j]=dp[i-1][j]
//当s[i-1]!=t[j-1]:不能用s[i-1]来匹配,s[i-1]匹配不了t[j-1],所以dp[i][j]=dp[i-1][j]
for(let i=1;i<=s.length;i++){
for(let j=1;j<=t.length;j++){
if(s[i-1]===t[j-1]){
dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
}else{
dp[i][j]=dp[i-1][j];
}
}
}
return dp[s.length][t.length];
};
这个问题可以看作是子问题重复的决策过程,符合动态规划解决问题的特征。
可以定义状态dp[i][j]为,s的前i个字符组成的子序列中,t的前j个字符出现的次数。
然后递推关系为:
如果s[i] == t[j],那么两种可能
- 使用s[i]匹配t[j]
- 不使用s[i] 如果s[i] != t[j],那么只有一种可能就是不使用s[i]
边界条件为: 当j=0时,t为空串,则dp[i][0] = 1
最后结果就是dp[s.length][t.length]