不同的子序列DP解释
来自LeetCode
给定一个字符串S和一个字符串T,计算S中不同子序列的个数。
字符串的子序列是由原始字符串形成的新字符串,通过删除字符中的一些(可以不是)而不干扰其余字符的相对位置。 (即“ACE”是“ABCDE”的子序列,而“AEC”不是)。
这里是一个例子:S =“兔子”,T =“兔子”
返回3。
我看到一个很好的DP解决方案,但是,我很难理解它,任何人都可以解释这个DP如何工作?
int numDistinct(string S, string T) {
vector<int> f(T.size()+1);
//set the last size to 1.
f[T.size()]=1;
for(int i=S.size()-1; i>=0; --i){
for(int j=0; j<T.size(); ++j){
f[j]+=(S[i]==T[j])*f[j+1];
printf("%dt", f[j] );
}
cout<<"n";
}
return f[0];
}
首先,尝试自己解决这个问题,以提出一个天真的实现:
假设S.length = m
和T.length = n
。 我们写S{i}
作为从i
开始的S
的子串。 例如,如果S = "abcde"
, S{0} = "abcde"
, S{4} = "e"
, S{5} = ""
。 我们对T
使用类似的定义。
令N[i][j]
为S{i}
和T{j}
的不同子序列。 我们对N[0][0]
感兴趣(因为它们都是完整的字符串)。
有两种简单的情况:对于任何i
, N[i][n]
,对于j<n
, N[m][j]
。 ""
在一些字符串S
中有多少个子序列? 正确1. ""
多少个T
? 只有0。
现在,给定一些任意的i
和j
,我们需要找到一个递归公式。 有两种情况。
如果S[i] != T[j]
,我们知道N[i][j] = N[i+1][j]
(我希望你自己可以证明这一点,我打算解释上面的神秘算法详细地说,不是这个天真的版本)。
如果S[i] = T[j]
,我们有一个选择。 我们可以'匹配'这些字符并继续与S
和T
的下一个字符,或者我们可以忽略匹配(就像在S[i] != T[j]
)。 既然我们有两种选择,我们需要在那里增加计数: N[i][j] = N[i+1][j] + N[i+1][j+1]
。
为了使用动态编程来查找N[0][0]
,我们需要填充N
表。 我们首先需要设置表格的边界:
N[m][j] = 0, for 0 <= j < n
N[i][n] = 1, for 0 <= i <= m
因为在递归关系的依赖关系,我们可以填写表循环的其余部分i
向后和j
转发:
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
if (S[i] == T[j]) {
N[i][j] = N[i+1][j] + N[i+1][j+1];
} else {
N[i][j] = N[i+1][j];
}
}
}
我们现在可以使用算法的最重要的技巧:我们可以使用一个一维数组f
,并在外部循环中使用不变量: f = N[i+1];
这是可能的,因为桌子被填满了。 如果我们将此应用于我的算法,则会得出:
f[j] = 0, for 0 <= j < n
f[n] = 1
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
if (S[i] == T[j]) {
f[j] = f[j] + f[j+1];
} else {
f[j] = f[j];
}
}
}
我们差不多就是你给的算法。 首先,我们不需要初始化f[j] = 0
。 其次,我们不需要赋值类型f[j] = f[j]
。
由于这是C++
代码,我们可以重写代码片段
if (S[i] == T[j]) {
f[j] += f[j+1];
}
至
f[j] += (S[i] == T[j]) * f[j+1];
就这样。 这产生了算法:
f[n] = 1
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
f[j] += (S[i] == T[j]) * f[j+1];
}
}
我认为答案很好,但有些东西可能不正确。
我认为我们应该通过i
和j
向后迭代。 然后我们将数组N
为数组f
,我们向前循环j
以便不重叠最后得到的结果。
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
if (S[i] == T[j]) {
N[i][j] = N[i+1][j] + N[i+1][j+1];
} else {
N[i][j] = N[i+1][j];
}
}
}
链接地址: http://www.djcxy.com/p/61507.html