蓝桥杯每日一题
一、题目
问题描述
输入格式
输出格式
二、解题
1.思路
最朴素的思想是用两层循环遍历s1和s2,一次次匹配直到成功。
但这里会出现一个问题,假设s1=ABABABA,s2=ABA,第一次匹配完成,i到达3,此时会忽略i=2时也能匹配的情况,如果每次i都要回退到i-=s2.size()+2的位置,时间复杂度会非常高,属于暴力解题。
#include<string>
#include<iostream>
using namespace std;
int main() {
string s1;
string s2;
cin >> s1;
cin >> s2;
int i;
int j;
for(i=0;i<s1.size();++i){
for(j=0;j<s2.size();++j){
if(s2[j]==s1[i]){
if(j==s2.size()-1){
i=i-s2.size()+2;
cout<<i;
break;
}
}
else{
j=-1;
}
i++;
}
}
return 0;
}
如果s1的ABA中,重复的前缀和后缀的间隔能够记录下长度len,这样就可以判断上述的第一次匹配完成之后问题,i应该回退到i-len的位置。
找前后缀的过程就是KMP算法的核心省时过程。这个算法还厉害在,他还考虑了i在任意位置匹配失败的时候的len值,并且可以多次回跳。用数组KMP[]记录。
2.代码
代码摘自洛谷
KMP数组,也就是next数组,下标的意义是匹配到模式串的第几位,索引是前面包括当前都匹配成功的情况下,下一位不匹配时,将模式串回退到索引值作为的新的下标的位置,继续与字符串判断。
例如:
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
模式串 | A | B | C | A | B | D |
索引 | 0 | 0 | 0 | 1 | 2 | 0 |
如果我们令i为前缀尾,j为后缀尾
int i;
int j;
int KMP[1000];
i=0;//前缀尾
j=1;//后缀尾
KMP[0]=0;//第二位匹配失败,模式串要跳回下标0,很容易理解
while(j<s2.size()){
//不相等时根据上一位记下的当前位不等时该跳去的地方跳转
//一直跳到能匹配或者干脆跳回0了
while(i>0&&s2[i]!=s2[j])i=KMP[i-1];
//匹配成功,i++,j++(循环)
if(s2[i]==s2[j]){
i++;
}
//i不仅代表着回调的索引,其实也代表着从第一位到前缀尾这段字符串的最长相同前后缀
KMP[j]=i;
j++;
}
核心代码:
j=0;
for(i=0;i<s1.size();i++){
if (s2.size() == 0) {
return 0;
}
while(j&&s2[j]!=s1[i])j=KMP[j-1];//如果失配 ,那么就不断向回跳,直到可以继续匹配
if (s2[j]==s1[i]) j++;//如果匹配成功,那么对应的模式串位置++
if (j==s2.size()) //一次匹配完了,假装这次匹配失败,继续往后匹配
{
cout<<i-s2.size()+1+1<<endl;
j=KMP[j-1];
}
}
全部:
#include<string>
#include<iostream>
using namespace std;
int main() {
string s1;
string s2;
cin >> s1;
cin >> s2;
int i;
int j;
int KMP[1000];
i=0;//前缀尾
j=1;//后缀尾
KMP[0]=0;
while(j<s2.size()){
//不相等时根据上一位记下的当前位不等时该跳去的地方跳转
//一直跳到能匹配或者干脆跳回0了
while(i>0&&s2[i]!=s2[j])i=KMP[i-1];
if(s2[i]==s2[j]){
i++;
}
KMP[j]=i;
j++;
}
j=0;
for(i=0;i<s1.size();i++){
if (s2.size() == 0) {
return 0;
}
while(j&&s2[j]!=s1[i])j=KMP[j-1];//如果失配 ,那么就不断向回跳,直到可以继续匹配
if (s2[j]==s1[i]) j++;//如果匹配成功,那么对应的模式串位置++
if (j==s2.size()) //继续匹配
{
cout<<i-s2.size()+1+1<<endl;
j=KMP[j-1];
}
}
for(i=0;i<s2.size();i++){
if(i==0){
cout<< KMP[i];
}
else{
cout<<" "<< KMP[i];
}
}
return 0;
}
总结
一个小BUG能改一年,我真的服了。