[leetcode每日一题]11.17
原创
©著作权归作者所有:来自51CTO博客作者YetiZ的原创作品,请联系作者获取转载授权,否则将追究法律责任
给定字符串 s
和字符串数组 words
, 返回 words[i]
中是s
的子序列的单词个数 。
字符串的 子序列 是从原始字符串中生成的新字符串,可以从中删去一些字符(可以是none),而不改变其余字符的相对顺序。
- 例如,
“ace”
是 “abcde”
的子序列。
示例 1:
输入: s = "abcde", words = ["a","bb","acd","ace"]
输出: 3
解释: 有三个是 s 的子序列的单词: "a", "acd", "ace"。
Example 2:
输入: s = "dsahjpjauf", words = ["ahjpjau","ja","ahbwzgqnuk","tnmlanowax"]
输出: 2
提示:
-
1 <= s.length <= 5 * 104
-
1 <= words.length <= 5000
-
1 <= words[i].length <= 50
-
words[i]
和s
都只由小写字母组成
Solution
首先遍历一遍字符串,开一个26行的二维数组按顺序记录字符串每个字母出现的下标。
之后对每一个word进行遍历。遍历的时候可以使用二分查找节约时间,不然可能会超时。
这里不久前学到的upper_bound()函数有了用武之地,自己写出来一遍过,还是非常有成就感的。
代码(C++)
class Solution {
public:
int numMatchingSubseq(string s, vector<string>& words) {
vector<vector<int>> idx(26, vector<int>());
for(int i=0;i<s.size();i++){
idx[s[i]-'a'].push_back(i);
}
int cnt = 0;
for(auto& word:words){
int cur = -1;
bool flag = true;
for(int i=0;i<word.size();i++){
int k = upper_bound(idx[word[i]-'a'].begin(), idx[word[i]-'a'].end(), cur, [=](int st, auto& j){return st<j;}) - idx[word[i]-'a'].begin();
if(k==idx[word[i]-'a'].size()){
flag = false;
break;
}
cur = idx[word[i]-'a'][k];
}
if(flag)cnt++;
}
return cnt;
}
};
让我看看题解怎么写的
题解让我明白了两件事:
一,我没有必要用lambda表达式重载查找函数。
二,可以用多指针来优化。
- 多指针思想转为存储words,然后遍历s,每个位置字母把对应的word往后移动,如果已经到word长度了,那就匹配上了,遍历结束没匹配完的就不是子序列