每天一道leetcode:115. 不同的子序列(动态规划&困难)

今日份题目:

给你两个字符串 st ,统计并返回在 s子序列t 出现的个数。

题目数据保证答案符合 32 位带符号整数范围。

示例1

输入:s = "rabbbit", t = "rabbit"
输出:3
解释:
如下所示, 有 3 种可以从 s 中得到 "rabbit" 的方案。
rabbbit选前两个b
rabbbit选后两个b
rabbbit选两头的b

示例2

输入:s = "babgbag", t = "bag"
输出:5

提示

  • 1 <= s.length, t.length <= 1000

  • st 由英文字母组成

题目思路

这道题目的思路和之前的子序列的思路不太一样的地方在于,这道题用到的是当前位置到字符串最后位置的子问题,而之前的题是当前位置到开头位置的子问题。

状态转移方程:

当 s[i]=t[j] 时,dp [ i ] [ j ]由两部分组成:

如果 s[i]和 t[j]匹配,则考虑 t[j+1:] 作为 s[i+1:]的子序列,子序列数为 dp [ i+1 ] [ j+1 ];

如果 s[i] 不和 t[j] 匹配,则考虑 t[j:] 作为 s[i+1:]的子序列,子序列数为 dp [ i+1 ] [ j ]。

因此当 s[i]=t[j] 时,有 dp [ i ] [ j ] =dp [ i+1 ] [ j+1 ]+dp[ i+1 ] [ j ]。

当 s[i]≠t[j] 时,s[i]不能和 t[j]匹配,因此只考虑 t[j:]作为 s[i+1:] 的子序列,子序列数为 dp[i+1] [j]。

因此当 s[i]≠t[j] 时,有 dp [ i ] [ j ]=dp [ i+1 ] [ j ]。

得状态转移总方程:

每天一道leetcode:115. 不同的子序列(动态规划&困难)_第1张图片

这道题目好难,我也是有点晕,如果大家有疑问,欢迎评论区讨论哦!

代码

class Solution 
{
public:
    int numDistinct(string s, string t) 
    {
        //获取两个字符串的长度
        int n= s.length();
        int m= t.length();
        if (n末尾]为空字符串,故对于任何字符串,空字符串都是其子序列,为1 
        {
            dp[i][m]=1;
        }

        //更新所有dp值
        for(int i=n-1;i>=0;i--) 
        {
            char sc=s[i];
            for(int j=m-1;j>=0;j--) 
            {
                char tc=t[j];
                if(sc==tc) 
                {
                    dp[i][j]=dp[i+1][j+1]+dp[i+1][j];
                } 
                else 
                {
                    dp[i][j]=dp[i+1][j];
                }
            }
        }
        return dp[0][0];
    }
};

提交结果

每天一道leetcode:115. 不同的子序列(动态规划&困难)_第2张图片

 欢迎大家在评论区讨论,如有不懂的代码部分,欢迎在评论区留言!

你可能感兴趣的:(动态规划,动态规划,leetcode,算法,职场和发展,c++,数据结构)