好位置
题目
给出两个串s和x,定义s中的某一位i为好的位置,当且仅当存在s的子序列
满足y=x且存在j使得i=kj成立。
问s中是否所有的位置都是好的位置。
输入
一行两个字符串s,x,这两个串均由小写字母构成。
1 <= |s|, |x| <= 200000
输出
Yes表示是。
No表示不是。
示例1
输入
abab
ab
输出
Yes
示例2
输入
abacaba
aba
输出
No
示例3
输入
abc
ba
输出
No
转载于:原版点击Here
(1)首先,说说这个题吧,看起来短小简单,然而根本看不懂
(2)(查的)题意:x是不是s的循环子串
(3)字符串匹配问题:首先,kmp
(4)因为要循环,所以有几个细节:
1.在kmp函数里,之前是找到即返回,现在当找到了,要标记主串匹配成功的末尾flag[i-1]=1,同时,把用于模式串的下标回溯,便于后续匹配j=next[j]
2.在main函数里,从后往前扫描主串,如果是循环模式串,则只有在循环节处,flag[l]=1,其余处,flag[i]=0。l为跳转到完成当前匹配字符串的前一个位置
#include<iostream>
#include<string.h>
using namespace std;
const int maxn=2e5+5;
int Next[maxn];
int flag[maxn];
void prefix(string t){
int j,k;
j=0,k=-1;
Next[0]=-1;
int len=t.length();
while(j<len){
if(k==-1||t[k]==t[j]){
j++;
k++;
Next[j]=k;
}
else{
k=Next[k];
}
}
}
void kmp(string s,string t){
int i=0,j=0;
int lens=s.length();
int lent=t.length();
while(i<lens){
if(j==-1||s[i]==t[j]){
i++;
j++;
}
else{
j=Next[j];
}
if(j==lent){//匹配成功
flag[i-1]=1;//对于匹配成功的进行末尾标记
j=Next[j];//j:回溯的位置 ,方便下次处理
}
}
}
int main(){
string s,t;
cin>>s>>t;
prefix(t);
memset(flag,0,sizeof(flag));
kmp(s,t);
int n=s.length();
int m=t.length();
int l=n;
int ok=1;
for(int i=n-1;i>=0;i--){
if(flag[i]){
l=i-m;//完成此次匹配前的一个位置
}
if(flag[i]==0&&l>=i){//其实l==i也可以
ok=0;//正常匹配情况下,当i>l时flag=0,flag[l]=1
break;
}
}
if(ok)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
return 0;
}