题目大意
判断一个字符串s
是否是另一个串t
的子序列。子序列指将一个字符串删除若干字符后组成的串。例如abc
是assdfbsc
的子序列。输入限制:
- 0 <= s.length <= 100
- 0 <= t.length <= 10^4
- 两个字符串都只包含小写字母
进阶:假如有超过10亿个s
串,一个t
串,怎么做会更好。
思路
对于一个s
和t
来说,可以直接从前往后判断,考虑s
中的字符在t
中最早出现位置即可。但是假如s
数目较大的话,一个一个判断就不能很好的利用t
只有一个的特性,因此可以利用最早出现位置的特性优化。
由于字符串中只包含小写字母,而t.length <= 10^4
,因此可以打表记录每个小写字母的出现位置。流程如下:
有效起始位置 = -1
对i从0到1
判断s[i]是否在 有效起始位置 后出现过 (二分查找)
未出现过 -> false
更新 有效起始位置 为s[i]出现的位置
true
判断是否出现过可以利用位置一定是从小到大的特性使用二分查找,对应STL中的upper_bound
。
另外就是边界情况:
- s.size() = 0
- t.size() = 0
- 对于s[0],有效起始位置 应为 -1
- s=aaaaaa,t=bbaaaa的情况(使用upper_bound而不是lower_bound)
代码
class Solution {
public:
bool isSubsequence(string s, string t) {
if (s.size() <= 0)
return true;
const int sz = t.size();
if (sz <= 0)
return false;
vector<vector<int>> table(26);
for (int i = 0; i < sz; i++) {
table[t[i] - 'a'].push_back(i);
}
int laPos = -1;
for (size_t i = 0; i < s.size(); i++) {
const char sc = s[i];
const int sci = sc - 'a';
auto it = upper_bound(table[sci].begin(), table[sci].end(), laPos);
if (it == table[sci].end())
return false;
laPos = *it;
}
return true;
}
};
总结
打表+二分。