模式匹配算法,不退化地在线性时间内完成模式匹配
目的:在目标串中找到模式串
作用:预处理出模式串的匹配信息,节省不必要的匹配时间
比如:有两个串 aacdeeaacc aacc
先匹配第一位,发现匹配,再匹配第二位,第三位,直到第四位不符合,此时,将搜索词aacc后移一位,重复上述操作,可以看出,后面的a【acdee】aacc acdee是没有必要比较的,可以直接匹配后面的aacc,所以,如何做到这一点呢?
实际上,我们的目的就是想让串越过一些没必要的部分,直接移到有匹配成功的可能的位置,那目标变为了怎样计算需要越过去的位数,这就用到了next[].
通俗一点,next[]记录的就是 前i位中前后缀的共有元素的最大值,我们称为记录“部分匹配”(字符串匹配过程中失配情况下可以向前多跳几个字符)
补充:
以aacdeeaacc为例,好像有点长,用abcde吧
前缀:a,ab,abc,abcd (除结尾字符)
后缀:bcde,cde,de,e (除开头字符)
“部分匹配”的实质是,字符串头,尾可能会有重复。比如,”abcdab”之中有两个”ab”,那么它的”部分匹配值”就是2(”ab”的长度)。搜索词移动的时候,第一个”ab”向后移动4位,就可以移动到第二个”ab”的位置。
即: 使串 移到部分匹配值所对应的后缀的位置
**移动位数=已匹配的字符数-对应的部分匹配值=中间越过的位数**
但要注意,遇到可以匹配上一部分的才可以用next后移到与它相同的后缀处,保证后面可以有匹配上的可能
//求模式串(所求串)在目标串(原串)中出现的次数 , 可重叠
#include<algorithm>
#include<cstring>
#include<cstdio>
#define N 1010
using namespace std;
char s[N],p[N];//所求串 , 原串
int nxt[N];//失配情况下可以向前多跳几个字符
//int len;
void get_nxt(char * p)//帮助越过没必要匹配的位置
{
int i=0,j=-1;
nxt[i]=j;//nxt[0]=-1;
while(p[i])//p不为空时,就是要记录完每个位置的nxt
{//i:1~n
if (j==-1||p[j]==p[i]) nxt[++i]=++j;
else j=nxt[j];
}
}
/*
void get_nxt()
{
int j=-1,i=0;
nxt[0]=-1;
while(i<len)
{
if(j==-1||ss[i] == ss[j])
{
i++;
j++;
nxt[i]=j;
}
else
{
j=next[j];
}
}
}
*/
int kmp(char *s,char *p)
{
get_nxt(p);//处理nxt
int i=0,j=0,ret=0;
for (;s[i];++i) //若 int i=1,则i++
{
while (j!=-1&&s[i]!=p[j]) j=nxt[j];
j++;
if (!p[j])
{
ret++;
j=nxt[j];
//operations
}
}
return ret;
}
int main()
{
scanf("%s%s",s,p);
// len=strlen(p);
printf("%d\n",kmp(s,p));
return 0;
}
@有错误,请指出哟(^U^)@