关于 KMP
发现KMP, 我都已经忘了,找到我之前写的总结,粘贴一下,保存留念吧;
发现之前我写的总结和你好玩的样子,自己都看笑了...hia hia hia hia...
KMP我只了解你一点点
KMP:即串模式匹配,(KMP分别是三个人名字的简称)。
学习KMP推荐:严蔚敏数据结构课件。真心说她讲的很到位。能让你明白next[],的求法。
简单算法基本思想(当字符串长度不大时):用i, j指主串和模式串。通过一个个比较,直至模式串与主串一一匹配则称匹配成功,否则失败。
改进办法:不用将i指针一次次回朔,而是利用以匹配的结果是是模式串尽可能的向前滑动。
这里需要一个next[100], 的函数。
函数模板:KMP() 与 get_next();(详见数据结构严蔚敏版,84页)
KMP应用:
http://acm.hdu.edu.cn/showproblem.php?pid=1711
代码如下:
#include<stdio.h>
#include<string.h>
int m, n, next[10005];
int xx[1000005], yy[10005];
void get_next()
{
int i, j;
i=1;
j=0; //j=1; j写成1,害我WA了N次
next[1]=0;
while(i<=n)
{
if(j==0||yy[i]==yy[j])
{
i++;
j++;
if(yy[i]!=yy[j])
next[i]=j;
else
next[i]=next[j];
}
else
j=next[j];
}
}
int KMP( )
{
int i, j;
i=1;
j=1;
while(i<=m && j<=n)
{
if(j==0||xx[i]==yy[j])
{
i++;
j++;
}
else
j=next[j];
}
if(j>n)
return i-n;
else
return -1;
}
int main()
{
int p, i, j;
scanf("%d", &p);
while(p--)
{
scanf("%d%d", &m, &n);
memset(xx, 0, sizeof(xx));
memset(yy, 0, sizeof(yy));
for(i=1; i<=m; i++)
scanf("%d", &xx[i]);
for(j=1; j<=n; j++)
scanf("%d", &yy[j]);
get_next();
printf("%d\n", KMP());
}
}
http://acm.hdu.edu.cn/showproblem.php?pid=2087
代码如下:
#include<stdio.h>
#include<string.h>
char str[1010], str1[1010];
int next[1010];
int len, len1;
void get_next()
{
int i, j;
i=0; j=-1; //*这里注意导致我WA不要写成 i=1; j=0;
next[0]=-1; //*不要把第一个弄没写成next[1]=0;
while(i<len1)
{
if(j==-1||str1[j]==str1[i])
{
j++;
i++;
if(str1[i]!=str1[j])
next[i]=j;
else
next[i]=next[j];
}
else
j=next[j];
}
}
int KMP()
{
get_next();
int i, j;
i=0;
j=0;
int sum=0;
while(i<len)
{
if(j==len1)
{
sum++;
j = 0;
}
if(str[i]==str1[j]||j==-1)
{
i++;
j++;
}
else
j = next[j];
}
if(j==len1)
sum++;
return sum;
}
int main( )
{
int i, j;
while(scanf("%s", str)&&(strcmp(str, "#")!=0))
{
scanf("%s", str1);
len = strlen(str);
len1 = strlen(str1);
int place = KMP();
printf("%d\n", place);
}
}
http://acm.hdu.edu.cn/showproblem.php?pid=2203
说这道题我的话就多了:
思想:将主串弄成一个环,然后与匹配串进行一一比较,省下了指针回朔的时间:
超时代码:
#include<stdio.h>
#include<string.h>
int main()
{
int i, j, len, len1;
char str[100005], str1[100005];
while(scanf("%s%s", str, str1)!=EOF)
{
len = strlen(str);
len1 = strlen(str1);
if(len<len1)
printf("no\n");
else
{
i = 0;
j = 0;
while(j<len1)
{
if(str[i]==str1[j])
{
str[i]=' ';
i=0;
j++;
}
else
i++;
if(i==len)
break;
}
if(j==len1)
printf("yes\n");
else
printf("no\n");
}
}
}
法一:利用字符数组,strstr()函数:找出str2字符串在str1字符串中第一次出现的位置(不包括str2的串结束符)。 返回值:返回该位置的指针,如找不到,返回空指针。
代码如下:
#include<stdio.h>
#include<string.h>
int main()
{
int i, j, len, len1;
char str[100005], str1[100005];
while(scanf("%s%s", str, str1)!=EOF)
{
len = strlen(str);
len1 = strlen(str1);
if(len<len1)
printf("no\n");
else
{
char str3[200005];
strcpy(str3, str);
strcat(str3, str);
if(strstr(str3, str1))
printf("yes\n");
else
printf("no\n");
}
}
}
法二:用string 串中的find()函数:find()函数是查找字串在str1中的位置,如果找不到就是string::npos,如果找到了就是在str1中的索引。
代码如下:
#include<stdio.h>
#include<string.h>
#include<string>
using namespace std;
int main()
{
int i, j, len, len1;
char str[100005], str1[100005];
string ss, st;
while(scanf("%s%s", str, str1)!=EOF)
{
len = strlen(str);
len1 = strlen(str1);
if(len<len1)
printf("no\n");
else
{
ss = str;
ss += str;
st = str1;
if(ss.find(st)!=string::npos) // string::npos 是string串的结束,串到头了
printf("yes\n");
else
printf("no\n");
}
}
}