给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"
是"abcde"
的一个子序列,而"aec"
不是)。
进阶:
如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?
示例 1:
输入:s = "abc", t = "ahbgdc" 输出:true
示例 2:
输入:s = "axc", t = "ahbgdc" 输出:false
思路:指针i指向s,指针j指向t,不断向前移动,进行匹配
class Solution {
public:
bool isSubsequence(string s, string t) {
int i=0;
int j=0;
while(i<s.size()&&j<t.size())
{
if(s[i]==t[j])
{
i++;
}
j++;
}
return i==s.size();
}
};
给定字符串 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
思路:
首先记录下t的每一个字符和它的对应下标
这样在遍历时,就可以借助 index 中记录的信息,二分搜索 index[c]
中恰好比 j 大的那个数,如下图,在 [0,2,6]
中搜索比 4 大的那个数,即6
注意:如果目标值不存在,那么左侧边界的二分查找会找到恰好比目标值大的最小的数的索引。
class Solution {
public:
int numMatchingSubseq(string s, vector<string>& words) {
unordered_map<char,vector<int>> mapping;
int res=0;
for(int i=0;i<s.size();i++)//存储s的每一个字符与它的对应下标
{
mapping[s[i]].push_back(i);
}
for(string word:words)
{
int i=0;
int j=0;//指向s的指针
for(i=0;i<word.size();i++)
{
char c=word[i];
if(mapping.count(c))
{
int index=left_find(mapping[c],j);
if(index==-1)
{
break;
}
else
{
//向前移动指针j
j=mapping[c][index]+1;
}
}
else//word中的字符在s中不存在,则不匹配
{
break;
}
}
if(i==word.size())//word中的字符全部匹配,则是子序列
{
res++;
}
}
return res;
}
//找到mapping[c]中恰好比j大的最小元素的下标索引
int left_find(vector<int>& position,int j)
{
int left=0;
int right=position.size();
while(left<right)
{
int mid=(left+right)/2;
if(position[mid]<j)
{
left=mid+1;
}
else if(position[mid]>j)
{
right=mid;
}
else
{
right=mid;
}
}
//mapping[c]中的元素都比j小,则left左侧边界就会一直向右直至和right相等,退出循环
if(left==position.size())
{
return -1;
}
return left;
}
};