题目
困难
给你两个字符串 s和 t ,统计并返回在 s 的 子序列 中 t 出现的个数,结果需要对 109 + 7 取模。
示例 1:
输入:s = "rabbbit", t = "rabbit"
输出:3
解释:
如下所示, 有 3 种可以从 s 中得到 "rabbit" 的方案。
++rabb++b++it++
++ra++b++bbit++
++rab++b++bit++
示例 2:
输入:s = "babgbag", t = "bag"
输出:5
解释:
如下所示, 有 5 种可以从 s 中得到 "bag" 的方案。
++ba++b**g**bag
++ba++bgba++g++
**b**abgb++ag++
ba**b**gb**ag**
babg++bag++
提示:
1 <= s.length, t.length <= 1000s和t由英文字母组成
面试中遇到过这道题?
1/5
是
否
通过次数
177K
提交次数
340.8K
通过率
51.9%
思路
注意!这是一道hard题!
看到xxx序列在xxx序列中xxx的个数、序列的最长xxx子序列、最长xxx串,最短xxx串这些题目,一眼就想到动态规划。
序列t在序列s的子序列中出现的次数,出现了两个序列的匹配,毫无疑问是二维dp,我们采用由前向后dp的思路,dpij来表示 t1:i 在 s1:j 的子序列中出现的次数。注意!由于动态规划一般要对边界值进行讨论,dp的下标从11开始,0......和......0用来做边界值的讨论。
对于这种两个字符串的动态规划,一般都是讨论 i 和 j 各自对应的字符是否相等来分类。
状态转移
1、如果ti-1!=sj-1,也就是 i 对应的字符和 j 对应的字符不相等的情况。
要实现 t1:i 和 s1:j 的匹配,因为两部分切片的最后一个字符不相等,所有只能祈求 t1:i 能不能和 s1:j-1 能不能匹配。
dpij=dpij-1。
2、ti-1==sj-1
两部分切片的最后一个字符相等,所以我们既可以选择两种匹配方法
a、ti-1 和 sj-1 匹配完成后,t1:i-1和t1:j-1匹配,这一部分的方案数量是 dpi-1j-1
b、ti-1不和sj-1匹配,这时就和ti-1!=sj-1一样,这一部分方案数量就是 dpij-1
dpij=dpi-1j-1+dpij-1
边界情况的讨论。
状态转移方程中,我们要用到dpi-1j-1,而我们的状态转移的循环是
for(int i=1;i<=m;i++){
for(int j=i;j<=n;j++){
if(t[i-1]!=s[j-1]){
dp[i][j]=dp[i][j-1];
}else{//t[i-1]和s[j-1]匹配+t[i-1]不和s[j-1]匹配
dp[i][j]=dp[i-1][j-1]+dp[i][j-1];
}
}
}
m是t串的长度,n是s串的长度。
从循环上看,j<i||i==0 这一部分是没有出现在循环里的,但是i-1和j-1能遍历到,所以我们必然要讨论。
i=0时,代表切片为空串,空串是任何串的子串,所以这一部分的初值为1。
j<i时,s串长度小于t串,这是不可能是子串,所以这一部分初值为0。
vector<vector<unsigned long long>> dp(m+1,vector<unsigned long long>(n+1,0));
//边界情况-->空字符串是任何字符串的子序列
for(int i=0;i<=n;i++){
dp[0][i]=1;
}
代码(注意数据范围和取模)
cpp
class Solution {
public:
const int mod=1e9+7;
int numDistinct(string s, string t) {
int n=s.length();
int m=t.length();
if(n<m) return 0;
//dp[i][j]-->t[1-i]在s[1-j]中出现的次数()
//防止边界条件判断,从[1][1]开始算
//long long都会超出数据范围
vector<vector<unsigned long long>> dp(m+1,vector<unsigned long long>(n+1,0));
//边界情况-->空字符串是任何字符串的子序列
for(int i=0;i<=n;i++){
dp[0][i]=1;
}
for(int i=1;i<=m;i++){
for(int j=i;j<=n;j++){
if(t[i-1]!=s[j-1]){
dp[i][j]=dp[i][j-1];
}else{//t[i-1]和s[j-1]匹配+t[i-1]不和s[j-1]匹配
dp[i][j]=dp[i-1][j-1]+dp[i][j-1];
}
}
}
int ans=dp[m][n]%mod;
return ans;
}
};