【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)
。