难度:困难
给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。
一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE"
是 "ABCDE"
的一个子序列,而 "AEC"
不是)
题目数据保证答案符合 32 位带符号整数范围。
示例 1:
输入:S ="rabbbit"
, T ="rabbit" 输出
:3
解释: 如下图所示, 有 3 种可以从 S 中得到"rabbit" 的方案
。 (上箭头符号 ^ 表示选取的字母)rabbbit
^^^^ ^^rabbbit
^^ ^^^^rabbbit
^^^ ^^^
示例 2:
输入:S ="babgbag"
, T ="bag" 输出
:5
解释: 如下图所示, 有 5 种可以从 S 中得到"bag" 的方案
。 (上箭头符号 ^ 表示选取的字母)babgbag
^^ ^babgbag
^^ ^babgbag
^ ^^babgbag
^ ^^babgbag
^^^
题目分析:
这个题目一看就是DP问题,但是没有列表的习惯,一想觉得难度太大。我们列表如下所示,进行匹配。找出规律。
1.状态转换方程:f[i][j] = f[i-1][j-1] + f[i][j-1](当字符匹配时,即t[i] == s[j](这里需要注意这里的坐标比f的坐标小1))
2.选择二维数组作为数据结构
3.初始化,将f[0][0] = 1, 上面第一行赋值为1,左边第一列赋值为0(除了第一个数)
参考代码:
class Solution {
public:
int numDistinct(string s, string t) {
vector<vector<long long> > dp(t.size()+1,vector<long long>(s.size()+1,0));
//初始化,最上面的那行置为1,是为了方便计算,看上面表格理解(leetcode上需要用long long )
for(long long i = 0; i < s.size()+1; i++)
dp[0][i] = 1;
for(long long i = 1; i < t.size()+1; i++)
{
for(long long j = 1; j < s.size()+1; j++)
{
//这里注意,相对于dp来说,多了一行一列,但是对于字符串来说没有,要减掉多出来了哪一行一列
if(t[i-1] == s[j-1])
dp[i][j] = dp[i-1][j-1] + dp[i][j-1];
else
dp[i][j] = dp[i][j-1];
}
}
return dp[t.size()][s.size()];
}
};