文档讲解:代码随想录
视频讲解:代码随想录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] + 1else: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. 举例
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] + 1else: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. 举例