代码随想录算法训练营第五十四天|392.判断子序列 115.不同的子序列

文档讲解:代码随想录

视频讲解:代码随想录B站账号

状态:看了视频题解和文章解析后做出来了

392.判断子序列 

class Solution:
    def isSubsequence(self, s: str, t: str) -> bool:
        dp = [[0] * (len(t)+1) for _ in range(len(s)+1)]

        for i in range(1, len(s) + 1):
            for j in range(1, len(t) + 1):
                if s[i-1] == t[j-1]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = dp[i][j-1]
        
        return dp[len(s)][len(t)] == len(s)
  •     时间复杂度:O(n^2)
  •     空间复杂度:O(n)

1. 确定dp数组的含义

dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]

这里用i,j表示 i-1,j-1 是为了给初始化留一行和一列,而且递推公式也更方便。

2. 确定递推公式

第一种情况:s和j的元素相等,dp[i][j] 在 dp[i-1][j-1] 的基础上 + 1

第二种情况:s和j元素不相等,相当于要删除掉 j 的 i 位元素再去做对比,那就是 dp[i][j] = dp[i][j-1]

3. dp数组初始化

从递推公式可以看出dp[i][j]都是依赖于dp[i - 1][j - 1] 和 dp[i][j - 1],所以dp[0][0]和dp[i][0]是一定要初始化的。

4. 确定遍历顺序

递推公式中的j是i和j之前的元素下标,所以从前往后递推。

5. 举例
代码随想录算法训练营第五十四天|392.判断子序列 115.不同的子序列_第1张图片

 115.不同的子序列 

class Solution:
    def numDistinct(self, s: str, t: str) -> int:
        dp = [[0] * (len(s) + 1) for _ in range(len(t) + 1)]

        for i in range(1, len(s) + 1):
            if t[0] == s[i-1]:
                dp[1][i] = dp[1][i-1] + 1
            else:
                dp[1][i] = dp[1][i-1]

        for i in range(2, len(t) + 1):
            for j in range(1, len(s) + 1):
                if t[i-1] == s[j-1]:
                    dp[i][j] = dp[i][j-1] + dp[i-1][j-1]
                else:
                    dp[i][j] = dp[i][j-1]

        return dp[-1][-1]
  •     时间复杂度:O(n^2)
  •     空间复杂度:O(n)

1. 确定dp数组的含义

dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。

2. 确定递推公式

  • s[i - 1] 与 t[j - 1]相等
  • s[i - 1] 与 t[j - 1] 不相等

当s[i - 1] 与 t[j - 1]相等时,dp[i][j]可以有两部分组成。

一部分是用s[i - 1]来匹配,那么个数为dp[i - 1][j - 1]。即不需要考虑当前s子串和t子串的最后一位字母,所以只需要 dp[i-1][j-1]。

3. dp数组初始化

初始化t的第一个字符对应的子字符串数量。

4. 确定遍历顺序

递推公式中的j是i和j之前的元素下标,所以从前往后递推。

5. 举例

代码随想录算法训练营第五十四天|392.判断子序列 115.不同的子序列_第2张图片

你可能感兴趣的:(算法,leetcode,职场和发展)