1. 程式人生 > >leetcode 115 Distinct Subsequences

leetcode 115 Distinct Subsequences

題目大意是給出兩個字串S和T,要求求出S中與T相匹配的子字串的數量。
子字串可以通過從S中刪除元素且不改變剩餘元素順序的方式得到。

想法1

這是個動態規劃題目,從題目的描述中其實就有陷阱,因為按照刪除方法的話很難以去構建狀態轉移方程。子字串的構建可以通過增加的方式,即每次找到一個S與T相匹配的字元,直到找齊,這個思想的遞迴解法很容易寫出來。當然,肯定會超時。

既然如此,可以按照類似的思想來構建狀態轉移方程。首先思考如何構建自狀態,考慮到T,既然要找與T相匹配的子字串,那麼能不能先找到所有與T的字首相匹配的子字串,再來找T呢?是可以的。

比如對於S=“babgbag”,T=“bag”,先考慮T="b"的情況下,這時候按照順序,S能找到的匹配個數為1 0 1 0 1 0 0

。當T="ba"時,上一個匹配的字元可以幫助這個快速搜尋,只需要求和即可,有0 1 0 0 0 3 0。當T="bag"時,有0 0 0 1 0 0 4,顯然,答案為最後一個的所有元素之和。

因此狀態轉移函式F[i][j] 的意義為對於T的字首T[0…i],以S[j]結尾的S的字首中可以構建出的子字串的數量。

很容易有F[i][j]=k=0j1F[i1][k]F[i][j] = \sum_{k=0}^{j-1}{F[i-1][k]},設s.length()=n,t.length()=m,程式碼的時間複雜度為O(nm2)O(nm^2),空間複雜度為O(nm)

程式碼很快就AC了,但是耗時16ms,只超過了5%左右的C++程式碼

原始碼:

class Solution {
public:
    int numDistinct(string s, string t) {
        vector<int> F(s.length()*t.length(),0);
        for(int i = 0;i<s.length();i++)
        {
            if(s[i]==t[0])
            {
                F[i] = 1;
            }
        }
for(int y = 1;y<t.length();y++) { for(int x = 0;x<s.length();x++) { int coordinate = x+y*s.length(); F[coordinate] = 0; if(s[x]==t[y]) { for(int k = 0;k<x;k++) { F[coordinate] += F[(y-1)*s.length() + k]; } } } } int sum = 0; for(int i = 0;i<s.length();i++) { sum+=F[i+(t.length()-1)*s.length()]; } return sum; } };