【leetcode】392. 判断子序列
leetcode 刷题笔记 - 392. 判断子序列
题目
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,”ace” 是”abcde” 的一个子序列,而”aec” 不是)。
进阶:
如果有大量输入的 S,称作 S1, S2, … , Sk 其中 k >= 10 亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?
1 | 示例 1: |
提示
1 | 0 <= s.length <= 100 |
思路一:动态规划
说明
还是用动态规划的思路,本题其实可以借鉴 1143. 最长公共子序列的思路,我们需要判断 s 是否为 t 的子序列,本质上就是判断 s 和 t 是否有公共子序列,且 s 本身就是 s 和 t 的最长公共子序列。
首先是定义 dp 数组,用一个二维数组来表示:dp[i][j]
代表 s 字符串 i-1 和 t 字符串中 j-1 的公共子序列长度为 dp[i][j]
。因为是 i-1 和 j-1,所以初始化的时候需要将长度加一。
1 | vector<vector<int>> dp(s.size() + 1, vector<int>(t.size() + 1, 0)); |
最终我们得到的 dp[s.size()][t.size()]
,就是 s 和 t 的公共子序列长度,这个长度应该等于 s 的长度,否则代表 s 不是 t 的子序列。
然后是定义递推公式,分为两种情况
s[i-1]==t[j-1]
,代表子序列可以扩张,即dp[i][j] = dp[i-1][j-1]+1
,含义是两个字符串中各上一位的公共子序列长度加一;s[i-1]!=t[j-1]
,代表子序列不能扩张,此时应该沿用 “上一次的结果”,注意这里和 1143 题目就有区别了,我们需要判断 s 是否为 t 的子序列,则只能从 t 中删除元素来匹配 s,所以只能是dp[i][j] = dp[i][j-1]
;
确定了递推公式,根据递推公式可知当前的 dp[i][j]
依赖于 i-1 和 j-1,所以必须从小到大遍历进行推导。因为我们 dp 数组的含义使用了 i-1 和 j-1,所以并不需要对 dp 数组的第 0 列和第 0 行进行单独初始化操作,构造函数里面统一初始化为全 0 就可以了。
代码
完整代码如下
1 | class Solution { |
空间复杂度和时间复杂度是 O(N^2)
思路二:直接遍历
这道题限制的条件很简单,s 是否为 t 的子序列本质上是 s 中的每个字符是否能按顺序的在 t 中出现。
那么我们只需要从头开始遍历 t 字符串,匹配上一个 s 中的字符后,就开始匹配下一个 s 中的字符,直到 t 字符串遍历完毕。
此时如果 s 字符串中已遍历的部分是 s 字符串的长度,那么就代表 s 是 t 的子序列。
1 | class Solution { |
空间复杂度是 O(1)
,时间复杂度是 O(N)
。
- 最新
- 最热
- 最早
- 作者
点击重新获取 | 打开控制台