题意就是,给出一个字符串S,接着会有n组查询,每组查询会有一个字符串s2,问你这个字符串是不是包含在S中。
这里的包含指的是,顺序不改变就行,不一定要紧挨着,一开始我看错了题目,直接上kmp,写了一半发现不行。
这题如果我们暴力去找,我们会发现,中间很多过程都是浪费的,比如S="acccccccccccccccccccccccccca",
如果我们要去判断s2="aa" 这个字符串在不在S中,中间这么多c都是无效比较。
那么其实如果能一步知道下一个字符的位置,那该多好,类似于kmp算法的next指针跳跃。这是一个质的飞跃压。
所以我们就可以预处理出一个二维数组 next[i][j] 表示第i个位置后面,字母a-z出现的位置,如果出现很多个,我们只记录最前面的,只记录最前面的我们能保证不会遗漏其他的。i最大是1e6,j最大就26,因为26个字母嘛
处理的时候,我们应该从后往前处理。
处理好这个二维next数组后,那么接下来直接for循环跑一边我们要查询的字符串就OK了
本弱刚开始因为在预处理的时候,字符串下标从0开始,一直有个小bug,改1开始就好了
下面给出1个小测试,供大家参考
aaaa
2
aaaa
aaaaa
Yes
No
代码有详细注释:
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+100;//maxlen
int q;//q组查询
char s[N];//模式串
char p[N];//匹配串
int _next[N][26]; //表示第i个位置后面'a'-'z'的
int last[26]; //用来存当前 'a'-'z'的位置
int main()
{
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=len-1;i>=0;i--)
{//我们从倒数第二位开始处理
last[s[i+1]-'a']=i+1;//由于我们是从倒数第二位开始的,首先把最后一位的位置算好
//算好之后,再copy给 _next[i][j]
for(int j=0;j<26;j++)
{
_next[i][j]=last[j];//第i为开始的后面26个字母是等于是他后面一位的26个字母的位置
}
}
scanf("%d",&q);
while(q--)
{
scanf("%s",p+1);
int len2=strlen(p+1);
if(len2>len)
{//如果比模式串都要长,不可能存在子串
printf("No\n");
continue;
}
bool f=false;
int pos=0;
for(int i=1;i<=len2;i++)
{
if(_next[pos][p[i]-'a'])
{
pos=_next[pos][p[i]-'a'];
}
else
{
f=true;
break;
}
}
if(!f)printf("Yes\n");
else printf("No\n");
}
return 0;
}
京公网安备 11010502036488号