LeetCode 笔记22 Distinct Subsequences 动态规划需要冷静
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]的队伍中了,如下图所示。
num[i - 1][j]: S还没到i,但其中一些同志们已经满足T[0: j-1]。符合条件的S[i - 1]到达,他们需要也加入到num[i][j]的队伍中,如下图所示。
(是不是觉得楼主疯了)
聪明的同学肯定要问了,但是初始状态大家都是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()]; }