哇哇哇!好难受,写了两个多小时,才通过全部样例。洛谷P1308
科普区(国内,国外)
在计算机科学中,Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个主文本字符串S
内查找一个词W
的出现位置。此算法通过运用对这个词在不匹配时本身就包含足够的信息来确定下一个匹配将在哪里开始的发现,从而避免重新检查先前匹配的字符。
这个算法是由高德纳和沃恩·普拉特在1974年构思,同年詹姆斯·H·莫里斯也独立地设计出该算法,最终由三人于1977年联合发表。(摘自维基百科)
kmp算法的核心思想是构造一个模式串构造一个数组标记模式串。数组标记当前位置在模式串中的最大前缀。当在与文本串比较的失败的时候,模式串直接返回到数组对应下标的位置。而不用直接返回模式串的开头的位置,重新从模式串的开头查找,从而达到在时间完成对字符串的查找。
题目理解
这道题的思想是使用字符串匹配,虽然可以直接使用string进行比较。题目比较简单就当练习一下字符串比较查找。题目中需要注意的是给模式串和文本串的最后加一个空格,用于简化判断字符串的比较。另一个需要注意的是在匹配同一字符串的时候要注意开头字符串的无空格,文本中间单词前要有空格。
AC代码
#include <iostream>
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
string s1,s2;
int next[10];
void getNext() {
int k=0;
memset(next,0,sizeof(next));
for(int i=1; i<s1.length(); i++) {
k = next[i-1];
if(s1[i]==s1[k]) {
next[i]=k+1;
} else {
while(true) {
int temp=next[k];
if(s1[i]==s1[temp]) {
next[i]=temp+1;
break;
}
if(temp<=0) {
next[i]=0;
break;
}
k--;
}
}
}
}
int main() {
getline(cin,s1);
getline(cin,s2);
s1 = s1 + " ";//添加空格简化问题
s2 = s2 + " ";
transform(s1.begin(),s1.end(),s1.begin(),::tolower);//字符串转小写
transform(s2.begin(),s2.end(),s2.begin(),::tolower);
getNext();//获取next数组
int ans=0;
int flag=-1;
int i=0,j=0;
while(i<s2.length()) {
while(i<s2.length() && j<s1.length() && s1.at(j)==s2.at(i)) {
if(j==s1.length()-1) {//结束
if((i-j==0) || (i-j>0 && s2[i-j-1]==' ')) {//判断前缀空格
ans++;//匹配字符串自增
if(flag==-1) {//获取第一位匹配字符
flag=i-j;
}
}
j=0;
break;//跳出循环
}
i++;
j++;
}
i++;
//**************
j=next[j];//划重点,next数组的运用
//**************
}
if(flag!=-1)
cout<<ans<<" "<<flag<<endl;
else
cout<<-1<<endl;
return 0;
}