题目
Given a string S and a string T, count the number of distinct subsequences of S which equals T.A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE"
is a subsequence of "ABCDE"
while "AEC"
is not).
具体例子见原题。
分析
肯定又是动态规划 。标准套路是构建dp数组,初始化第一行和第一列,找出递推公式。但是不同的题目对应着不同的递推公式,第一次见到一种题型很难直接找到递推公式,所以只能积累,或者:自己先手动完成一个dp数组然后找规律。
该题目的例子是Input: S = "rabbbit", T = "rabbit" Output: 3,在此基础上构建的dp数组如下:
Ø r a b b b i t
Ø 1 1 1 1 1 1 1 1
r 0 1 1 1 1 1 1 1
a 0 0 1 1 1 1 1 1
b 0 0 0 1 2 3 3 3
b 0 0 0 0 1 3 3 3
i 0 0 0 0 0 0 3 3
t 0 0 0 0 0 0 0 3
如果t的长度大于s的长度,那必然是0.然后如果t的长度为0的话,那必然是1.因为空串也算作一个子串。
我们通过观察上面的二维数组可以发现,当更新到dp[i][j]时,dp[i][j] >= dp[i][j - 1] 总是成立,再进一步观察发现,当 t[i - 1] == s[j - 1] 时,dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 1],若不等, dp[i][j] = dp[i][j - 1],所以,综合以上,递推式为:
dp[i][j] = dp[i][j - 1] + (s[i - 1] == t[j - 1] ? dp[i - 1][j - 1] : 0)
我花了一段时间区试图理解这个规律背后的含义,但是想了半天感觉还是有点乱。动态规划最根本的部分无非就是递推公式,但是这个递推不是随随便便就能推出来的,所以最好的解决方式还是多做题多积累。
代码
class Solution {
public:
int numDistinct(string s, string t) {
int row = t.size();
int col = s.size();
int dp[row+1][col+1] = {0};
for(int i=0;i<=col;i++) dp[0][i] = 1;
for(int i=1;i<=row;i++) dp[i][0] = 0;
for(int i=1;i<=row;i++)
for(int j=1;j<=col;j++)
{
dp[i][j] = dp[i][j - 1] + (t[i - 1] == s[j - 1] ? dp[i - 1][j - 1] : 0);
}
return dp[row][col];
}
};