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 = 0 j − 1 F [ i − 1 ] [ k ] F[i][j] = \sum_{k=0}^{j-1}{F[i-1][k]} F[i][j]=k=0j1F[i1][k],设s.length()=n,t.length()=m,代码的时间复杂度为 O ( n m 2 ) O(nm^2) O(nm2),空间复杂度为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;
    }
};

想法2

想法2更快也更简洁,这次将状态转移方程T[i][j]视为s[0…j]与t[0…i]匹配后的所有子字符串个数。
s [ j ] = = t [ i ] 时 T [ i ] [ j ] = T [ i − 1 ] [ j − 1 ] + T [ i ] [ j − 1 ] s[j]==t[i]时T[i][j]=T[i-1][j-1]+T[i][j-1] s[j]==t[i]T[i][j]=T[i1][j1]+T[i][j1],表示两个去掉这个匹配字符后产生的子字符串个数加上模版串增加这个字符后新增的子字符串个数
s [ j ] ! = t [ i ] 时 , T [ i ] [ j ] = T [ i ] [ j − 1 ] s[j]!=t[i]时,T[i][j]=T[i][j-1] s[j]!=t[i]T[i][j]=T[i][j1],同一模板内没有匹配上的话子字符串数量是不变的。
边界条件 T [ 0 ] [ . . . ] = 1 T[0][...] = 1 T[0][...]=1,即模板串为空的时候所有原字符串都能匹配上。

class Solution {
public:
    int numDistinct(string s, string t) {
        int M = t.size();
        int N = s.size();

        if (M == 0 || N == 0)
            return 0;

        int T[M+1][N+1] = { 0 };
        for (int j = 0; j <= N; ++j)
            T[0][j] = 1;

        for (int i = 1; i <= M; ++i)
            for (int j = 1; j <= N; ++j)
            {
                T[i][j] = (t[i-1] != s[j-1]) ? T[i][j-1] :
                          T[i-1][j-1] + T[i][j-1];
            }

        return T[M][N];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值