问题:给定两个字符串S,T,对于S,可以删除其中的任意多个(包括0)字符,使其得到T。问有多少种删法可以得到T。
举例分析:
S:ababa
T: aba
dp[i][j] : 表示 S 从0 ~ i - 1,T从0~j - 1,所得到的方法数。i,j 表示长度。
初始条件:dp[i][0] = 1,T为空串,而空串总是任意串的字串。即,将S串的所有字符都删掉,就得到T。
状态转移方程:
dp[ i ] [ j ] = dp[ i - 1] [ j - 1] + dp[ i - 1] [ j ] ; if S[i - 1] == T[ j - 1]
dp[ i ] [ j ] = dp[i - 1] [ j ]; else.
第一个状态转移方程表示,当S[i - 1] == T[ j - 1]时,我可以将T[j - 1] 认为是从S[i - 1] 得到,也可以认为不是。这是两种情况,最后的结果应该是两种情况的和。
按着状态转移方程,我们通过填表,得到结果如上图所示,其中第一列黑色的 1 为初始状态。每一行相同的颜色是我们通过一次遍历得到的结果。最终的结果为 右下角的 4.
//code
int numDistinct( string S, string T){ int lenT = T.size(); int lenS = S.size(); if(lenS < lenT) return 0; vector<vector<int> > dp(lenS + 1, vector<int>(lenT + 1, 0)); for (int i = 0; i <= lenS; ++i) dp[i][0] = 1; for (int i = 1; i <= lenS; ++i) for(int j = 1; j <= lenT; ++j) { if(T[j - 1] == S[i - 1]) dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]; else dp[i][j] = dp[i - 1][j]; } return dp[lenS][lenT]; }
通过状态转移方程,我们发现, 第 i 行只跟第 i - 1 行有关系,所以可以简化dp表,只用两行来进行迭代。但是这样每一行的第一个元素都很特别,都是 1 ,就使得我们在迭代的时候稍微麻烦些,我们换一下行列。当然我们也可以按列填表,但是我们总是习惯按行处理,至少笔者如此。
如此一来,所有的初始化就在同一行了,
int numDistinct(string S, string T) { int lenT = T.size(); int lenS = S.size(); if(lenS < lenT) return 0; //dp[0][i] = 1. vector<int> dp_pre(lenS + 1, 1); for (int i = 1; i <= lenT; ++i) { vector<int> dp_cur(lenS + 1, 0); for (int j = 1; j <= lenS; ++j) { if(T[i - 1] == S[j - 1]) dp_cur[j] = dp_pre[j - 1] + dp_cur[j - 1]; else dp_cur[j] = dp_cur[j - 1]; } dp_pre = dp_cur; } return dp_pre[lenS]; }
【leetcode】Distinct Subsequences,布布扣,bubuko.com
时间: 2024-12-30 02:00:01