[Leetcode] 115. 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.

兩種做法,第一種是recursion:

舉個例子,比如String T = "abc" String S = "abcabc"

當T裏的某一位,比如說第一位,"a" 匹配上S裏的某一位,也比如說第一位裏的"a",那麼有兩種情況

1. 用上這個匹配,我們再去遞歸求String T = "bc" 在String S ="bcabc"裏出現的次數,這裏就有三次,也就是說"abc"在"abcabc"中也有三次,因爲兩個String首字母a是相同的,我們用上這個

2. 或者不用這個匹配,我們遞歸去求String T = "abc"  在String S = "bcabc"裏出現的次數,這裏就是一次。

所以總共是4次。

public class Solution {  
    public int numDistinct(String S, String T) {  
        if (T.length()==0) return 1;  
        if (S.length()==0) return 0;  
        if (T.length()>S.length()) return 0;  
        if (T.charAt(0)!=S.charAt(0))  
            return numDistinct(S.substring(1),T);  
        else return numDistinct(S.substring(1),T) + numDistinct(S.substring(1),T.substring(1));  
    }  
}  


還可以用DP,一般兩個字符串匹配很容易想到的就是DP,和recursion的思想是差不多的。

dp[i][j]代表String T的前i位與String S前j位存在序列的個數,和Interleaving String ,Edit Distance差不多

用我們剛纔Recursion做出的歸納:當S中某個字符和T中某個字符匹配的時候:

1. 如果兩個字符相同,用這個字符,在矩陣裏的表示便爲累加上之前dp[i-1][j-1]的值

2. 不用這個字符,在矩陣裏的表示便爲累加上之前dp[i][j-1]的值

如果S的第i個字符和T的第j個字符相同,那麼所有dp[i-1][j-1]中滿足的結果都會成爲新的滿足的序列,當然dp[i-1][j]的也仍是可行結果,所以dp[i][j]=res[i-1][j-1]+res[i-1][j]。

遇到這種兩個串的問題,很容易想到DP。但是這道題的遞推關係不明顯。可以先嚐試做一個二維的表int[][] dp,用來記錄匹配子序列的個數(以S="rabbbit",T = "rabbit"爲例):

    r a b b b i t

  1 1 1 1 1 1 1 1

0 1 1 1 1 1 1 1

a 0 1 1 1 1

b 0 0 2 3 3 3

b 0 0 0 0 3 3 3

i 0 0 0 0 0 0 3 3

t 0 0 0 0 0 0 0 3  

從這個表可以看出,無論T的字符與S的字符是否匹配,dp[i][j] = dp[i][j - 1].就是說,假設S已經匹配了j - 1個字符,得到匹配個數爲dp[i][j - 1].現在無論S[j]是不是和T[i]匹配,匹配的個數至少是dp[i][j - 1]。除此之外,當S[j]和T[i]相等時,我們可以讓S[j]和T[i]匹配,然後讓S[j - 1]和T[i - 1]去匹配。所以遞推關係爲:

dp[0][0] = 1; // T和S都是空串.

dp[0][1 ... S.length() - 1] = 1; // T是空串,S只有一種子序列匹配。

dp[1 ... T.length() - 1][0] = 0; // S是空串,T不是空串,S沒有子序列匹配。


比如rabb和rab,如果我們不用rabb的b,就看rab有多少個rab子串,如果我們用rabb的b,也就是說rabb的b和rab的b匹配,我們只要看rab和ra的匹配數即可。
public class Solution {
    public int numDistinct(String S, String T) {
        if(S == null || T == null || S.length() < T.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 <= T.length(); j++){
                num[i][j] += num[i - 1][j];
                if(S.charAt(i - 1) == T.charAt(j - 1)){
                    num[i][j] += num[i - 1][j - 1];
                }
            }
        }
        return num[S.length()][T.length()];
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章