难度:困难
给定一个字符串 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> > f(t.size()+1,vector<long long>(s.size()+1,0));
if(t.empty())
return 1;
if(s.empty())
return 0;
//初始化状态转换方程最上面一行和最左边一列
f[0][0] = 1;
for(long long i = 1; i < s.size(); i++)
{
f[0][i] = 1;
}
for(long long i = 1; i < t.size(); i++)
{
f[i][0] = 0;
}
//填表
for(long long i = 1; i <= t.size(); i++)
{
for(long long j = 1; j <= s.size(); j++)
{
if(t[i-1] == s[j-1])//注意这里的坐标
f[i][j] = f[i-1][j-1] + f[i][j-1];
else
f[i][j] = f[i][j-1];
}
}
return f[t.size()][s.size()];
}
};