LeetCode 笔记22 Distinct Subsequences 动态规划需要冷静

时间:2022-02-02 05:54:19

Distinct Subsequences

Given a string S and a string T, count the number of distinct subsequences of T in S.

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).

Here is an example:
S = "rabbbit", T = "rabbit"

Return 3.

其实这道题本来不是很难,因为一看就是动态规划。结果笨娃(哎,真是笨娃啊)搞这个递推式搞了很久。所以记录一下。

Instinctly,(真心发现既然是dp,就往这方面想就是)假设S取前面i个字符(最后一个index是i - 1), T取前面j个字符(最后一个index是j - 1),那么在前i个字符中,有序列的个数num[i][j]的公式应该怎么写呢?

首先,如果S[i - 1] 不等于T[j - 1],那么num[i][j] = num[i - 1][j]。不难理解啊,就是S往前缩一个呗,反正也匹配不了T[j - 1]是不是?

如果S[i - 1]等于T[j - 1], 那么,num[i][j]应该是: num[i - 1][j - 1] + num[i - 1][j]。

为啥呢?

num[i - 1][j - 1]: S中还没到i的同志们在翘首盼望着i ,同样T中的乡亲们也在等待j 。符合条件的S[i - 1]一到达,他们就自然加入到num[i][j]的队伍中了,如下图所示。

LeetCode 笔记22 Distinct Subsequences 动态规划需要冷静

num[i - 1][j]: S还没到i,但其中一些同志们已经满足T[0: j-1]。符合条件的S[i - 1]到达,他们需要也加入到num[i][j]的队伍中,如下图所示。

LeetCode 笔记22 Distinct Subsequences 动态规划需要冷静

(是不是觉得楼主疯了)

聪明的同学肯定要问了,但是初始状态大家都是0,没见到+1啊。这里有个特殊的初始化,就是num[i][0] = 1。这好像在说,空串始终匹配整个串S

代码如下:

public int numDistinct(String S, String T) {
if (T.length() > S.length()) {
return 0;
}
int[][] num = new int[S.length() + 1][T.length() + 1];
for (int i = 0; i <= S.length(); i++) {
num[i][0] = 1;
}
for (int i = 1; i <= S.length(); i++) {
for (int j = 1; j <= Math.min(i, T.length()); j++) {
if (S.charAt(i - 1) == T.charAt(j - 1)) {
num[i][j] = num[i - 1][j - 1] + num[i - 1][j];
} else {
num[i][j] = num[i - 1][j];
}
}
} return num[S.length()][T.length()];
}