这种算法用于查找子序列,与之比较像的KMP用来查找子串。两者都提供了高效的查找。
模板题:https://ac.nowcoder.com/acm/contest/20960/1033
算法思想:假设母序列为s1,我们可以把s1的每个字符后面的每种字母出现的第一个位置用nxt数组记录下来,要是哪种字母不存在就标记为-1. 为了实现这个想法,我们可以倒序遍历s1。若当前遍历到的字母下标为i,用last数组记录s1[i]的位置,遍历到第i-1个字母时,last存放的就是字母i的位置。
当我们要查找子序列s2时,假设s2是"morty",就可以直接通过nxt[m][o]获得s1中m后面o的第一个位置。
#include<iostream>
#include<cstring>
using namespace std;
int nxt[1000010][26];
int last[26];
int main(){
memset(last,-1,sizeof(last)); //初始化last全为-1,代表最后一个字符后面没有字符
string s1;
cin>>s1;
int n=s1.size();
for(int i=n-1;i>=0;i--){
for(int j=0;j<26;j++){
nxt[i][j]=last[j]; //记录s1[i]后面每种字母的位置
}
last[s1[i]-'a']=i; //更新last
}
int x;
cin>>x;
while(x--){
string s2;cin>>s2;
bool flag=1;
int pos=last[s2[0]-'a']; //子序列首字母位置
if(pos==-1) {
cout<<"No"<<endl;
continue;
}
for(int i=1;i<s2.size();i++){
pos=nxt[pos][s2[i]-'a']; //获得下一个字母位置
if(pos==-1){
cout<<"No"<<endl;
flag=0;
break;
}
}
if(flag) cout<<"Yes"<<endl;
}
return 0;
}