最后更新于
最后更新于
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
示例 1:
示例 2:
后续挑战 :
如果有大量输入的 S,称作S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?
使用贪心思路, 本题很简单. 从t
的第一个字母开始, 逐个遍历寻找s
中的字符, 每找到s
中的一个字符, 就寻找s
中的下一个字符, 直到:
遍历完t
, 但s
还有剩余的字符, 说明不匹配
s
中的每一个字符都在t
中找到了对应的字符, 说明匹配
贪心的思路就是对于s
中的每个字符, 我们只需要找到t
中剩余字符中的最左侧的匹配位置, 因此如果一个偏右的位置匹配, 并最终s
和t
完全匹配, 那么将这个字符的匹配换成最左侧的位置, s
和t
肯定也是完全匹配的.
对于一个s
, 从s
的第一个字符开始, 找每个字符在t
中合适的位置. 如果需要判断多个s
是否与t
匹配, 我们可以先遍历一遍t
, 记录每个字符在t
中的所有位置. 这是因为对于某个s
中的某个字符s[i]
, 我们在寻找位置时, 只会跟当前这个字符所在的所有位置匹配, 这样就可以使用二分方法来搜索了.
对于s
中的每个字符s[i]
, 我们记录上一个字符s[i - 1]
在t
中的位置pos
(对于s[0]
来说, 上一个字符的位置定义为-1), 然后我们要在pos + 1
到位置是否在t
中这个字符对应的索引列表的范围内, 如果在, 我们要找到不小于pos + 1
的第一个位置. 因此, 以pos + 1
为目标, 对这个有序的索引列表进行二分搜索, 如果中间位置小于目标就移动left
, 否则移动right
, 最终left
停留的位置, 就是不小于pos + 1
的第一个位置, 但如果left
已经越界, 说明没有满足的字符, 即不匹配.
后续挑战的答案:
这样能够在的时间复杂度下完成判断.
这里考虑到后续挑战, 要对大量的s
, 判断每一个是否匹配, 这样的时间复杂度就有些慢了. 可以通过二分的方法, 将一个s
判断的时间从, 降到.
图解逻辑可参考: