leetcode115.不同的子序列(动态规划)

题目描述
给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。
字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,“ACE” 是 “ABCDE” 的一个子序列,而 “AEC” 不是)
在这里插入图片描述
问题:s中与t相同的子序列的个数
子问题:s的子串中与t相同的子序列的个数
状态F(i, j):s的前i个字符构成的子串中与t前j个字符相同的子序列的个数
if(s[i] == t[j]):
如果使用第i个字符,那这个字符只能作为子序列最后一个字符,相当于和t的第j个字符匹配:
F(i - 1, j - 1)
如果不使用第i个字符:F(i - 1, j)
例如s:rabbb,t:rabb
此时s的第五个字符和t的第四个字符相同,s[5] == t[4],
此时如果使用s的第五个字符,rabbb rabb
意味着要在s的前4个字符中找与t前3个字符相同的子序列个数,
F(4, 3):rabb或者rabb,然后在加上最后的s[5]就是F(5, 4);
如果不使用s的第五个字符,代表在s的前4个字符中找和t前4个字符相同的子序列的个数,也就是在s:rabb中找t:rabb,所以结果就一个rabb
F(4, 4):rabb
可以看出这两种状态并不重复,所以
if(s[ i ] == t [ j ]):
F(i, j) :F(i - 1, j - 1) + F(i - 1, j)
if(s[i] != t[j])这种状态下肯定不能使用第i个字符,所以状态退化到上一个字符,F(i, j) :F(i - 1, j)
画个图:
行表示字符串s,列表示字符串t,每一个格子表示s的前i个字符构成的子串中与t前j个字符相同的子序列的个数
在这里插入图片描述
假设t中有一个空字符串,s中任意长度字符串都可以构成这个空串,所以第一列初始化为1,
而一旦横坐标小于纵坐标,说明s字符串的长度小于t,这种情况下,t根本不可能是s的子序列,就全设置为0。
代码

class Solution {
    
    
public:
    int numDistinct(string s, string t) {
    
    
        int row = s.size() + 1;
        int col = t.size() + 1;
        vector<vector<unsigned long long>> dp(row, vector<unsigned long long>(col));
        dp[0][0] = 1;
        for(int i = 1; i < row; ++i)
        {
    
    
            dp[i][0] = 1;
            for(int j = 1; j < col; ++j)
            {
    
    
                if(i < j)
                    break;
                if(s[i - 1] == t[j - 1])
                    dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
                else
                    dp[i][j] = dp[i - 1][j];
            }
        }
        return dp[row - 1][col - 1];
    }
};

另外跟着图走一遍就会发现美每个状态都是根据上一行推出的,所以可以对代码进行优化,用一维数组就可以,但是需要注意的是,状态的推导要从后向前,如果从前往后更新数据,就变成由自己的一行推出的,导致错误。
代码

class Solution {
    
    
public:
    int numDistinct(string s, string t) {
    
    
        int col = t.size() + 1;
        vector<unsigned long long> dp(col);
        dp[0] = 1;
        for(int i = 0; i < s.size(); ++i)
        {
    
    
            for(int j = col - 1; j >= 1; --j)
            {
    
    
                if(s[i] == t[j - 1])
                    dp[j] += dp[j - 1];
            }
        }
        return dp[col - 1];
    }
};

Guess you like

Origin blog.csdn.net/weixin_45806959/article/details/122456391