115. 不同的子序列(动态规划)
给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。
一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,“ACE” 是 “ABCDE” 的一个子序列,而 “AEC” 不是)
题目数据保证答案符合 32 位带符号整数范围。
解题思路: 观察此题属于求子序列的问题,联想到用DP解题,然后定义dp[i][j]
表示字符串s前j个字符中包含字符串t前i个字符的个数,但是到这儿就断片儿了,参考了一下grandyang大神的思路,发现通过列举找出了状态转移方程,按照这个思路解完题后,想了想,如果不通过列举,可不可以这么找到状态转移方程,一般来说,想找出状态转移方程我们需要先列出上一个状态有哪些,然后当前状态与上一个状态的关联是什么,另外一点是,在分解上一个状态时,要找一个标准,使得分解的状态互斥、完备,OK,我们相信上一个状态是不是可以分解为[i-1,j],[i,j-1],[i-1][j-1]
,(t->s),但是对于状态[i,j-1]是不需要且不成立的,因为s先增长,t后增长才有意义,那剩下的就是状态[i-1,j]
和状态[i-1][j-1]
,对于状态[i-1][j-1]
要求s[j]==st[i]
才能对状态[i][j]
有贡献,OK,至此,即可分析出状态转移方程~
// dp[i][j] = dp[i][j - 1] + (T[i - 1] == S[j - 1] ? dp[i - 1][j - 1] : 0)
class Solution {
public:
int numDistinct(string s, string t) {
int m = t.size(), n = s.size();
vector<vector<long>> dp(m + 1, vector<long>(n + 1, 0));
for (int j = 0; j <= n; ++j) dp[0][j] = 1;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
dp[i][j] = dp[i][j - 1] + (t[i - 1] == s[j - 1] ? dp[i - 1][j - 1] : 0);
}
}
return dp[m][n];
}
};
————————————
参考资料:
https://www.cnblogs.com/grandyang/p/4294105.html