1. 程式人生 > >[LeetCode] Distinct Subsequences 不同的子序列

[LeetCode] 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.

看到有關字串的子序列或者配準類的問題,首先應該考慮的就是用動態規劃Dynamic Programming來求解,這個應成為條件反射。而所有DP問題的核心就是找出遞推公式,想這道題就是遞推一個二維的dp陣列,下面我們從題目中給的例子來分析,這個二維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

首先,若原字串和子序列都為空時,返回1,因為空串也是空串的一個子序列。若原字串不為空,而子序列為空,也返回1,因為空串也是任意字串的一個子序列。而當原字串為空,子序列不為空時,返回0,因為非空字串不能當空字串的子序列。理清這些,二維陣列dp的邊緣便可以初始化了,下面只要找出遞推式,就可以更新整個dp陣列了。我們通過觀察上面的二維陣列可以發現,當更新到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] + (T[i - 1] == S[j - 1] ? dp[i - 1][j - 1] : 0)

根據以上分析,可以寫出程式碼如下:

class Solution {
public:
    int numDistinct(string S, string T) {
        int dp[T.size() + 1][S.size() + 1];
        for (int i = 0; i <= S.size(); ++i) dp[0][i] = 1;    
        for (int i = 1; i <= T.size(); ++i) dp[i][0] = 0;    
        for (int i = 1; i <= T.size(); ++i) {
            for (int j = 1; j <= S.size(); ++j) {
                dp[i][j] = dp[i][j - 1] + (T[i - 1] == S[j - 1] ? dp[i - 1][j - 1] : 0);
            }
        }
        return dp[T.size()][S.size()];
    }
};