首页 > 代码库 > Distinct Subsequences----匹配个串串

Distinct Subsequences----匹配个串串

题目大意

     给定母串S和待匹配串T,求T能在母串S中匹配多少次(不一定要连续匹配,并且母串中多个相同字母可以依次使用,但均只能使用一次,如S=rabbbit  T=rabbit, 则S中三个连续的b可以依次匹配T中两个bb各一次())

解题思路

     字符串匹配并且要求结果只为一个数字的时候,很多情况都是使用DP,这题也不例外,建立数组dp[i][j]表示按题目要求当前T串前i个字符匹配S串前j个字符的匹配结果。

建立转移方程:

当T[i] != S[j] 时,显然其值不会改变,因此dp[i][j] = dp[i][j-1];

当T[i] == S[j] 时,此时可以考虑从两个方向转移到当前dp[i][j];

第一个方向:dp[i-1][j-1],将T[0...(i-1)]记为T‘ ,表示在T‘尾部增加一个当前字符;

第二个方向:dp[i][j-1],将T[0...(i)]记为T‘‘ ,表示替换掉T’‘尾部的一个字符(必与当前字符相同);

由于整个过程只用从T的前一步状态转移而来,因此使用一个2*n(n为母串S的长度)的二维数组就能实现dp全过程。

总结

      重点考虑匹配串T,分析其每扩展一个字符后,可由哪些原来的状态转移到新的当前状态来。这道题目想到了就不是很难,主要是多了一些不必要的判断,不过为了保证程序易读且正确,加上这些判断也是值得的,可以后期逐步求精。

代码

class Solution {
public:
    int numDistinct(string S, string T) 
    {
        
        int n = S.length();
        int m = T.length(); 
        if (m > n)return 0;
        int dp[2][11000];   
        bool jud = false;
        memset(dp, 0, sizeof(dp));
        int index = 0;
        for (int i = 0; i < n; i ++){
            if (S[i] == T[0]){
               if (!jud){
                  jud = true;
                  dp[index][i] = 1;
               }
               else dp[index][i] = dp[index][i-1]+1;
            }
            else if (i)  dp[index][i] = dp[index][i-1];
        }
        for (int i = 1; i < m; i ++){
            jud = false;
            index^=1;
            
            for (int j = i; j < n; j ++){
                if (T[i] == S[j]){
                   if (!jud){
                      jud = true;
                      dp[index][j] = dp[index^1][j-1];
                   }
                   else  dp[index][j] = dp[index^1][j-1]+dp[index][j-1];
                } 
                else dp[index][j] = dp[index][j-1];
                
            }    
            for (int j = 0; j < n; j ++)   dp[index^1][j] = 0;
        }    
        return dp[index][n-1];
    }
};



Distinct Subsequences----匹配个串串