标签:
kmp又称烤(k)馍(m)片(p)算法,实际上是通过模式串本身的特性来优化模式串的匹配
next[j]表示j之前的字符串中有长度为next[j]的相同前缀后缀
失配时移动位置=失配字符所在位置-失配字符对应的next值,即j-next[j]
next[0]=-1 表示当0位置失配时,要将字符串向右移1位
1.求next数组:
next[j]表示j之前的字符串中有长度为next[j]的相同前缀后缀
求next数组的过程相当于模式串自己和自己匹配
void getNext() { int i,j; i=0;j=-1;next[0]=-1; while(i<tlen) { if(j==-1||t[i]==t[j])next[++i]=++j; else j=next[j]; } }
2.用next数组求最小循环节的长度:
如果一个字符串可以由k个某一子串组成,那么 这个字符串的最小循环节为该子串,循环周期为k。
如abcd最小循环节为abcd,abcabc最小循环节为abc
怎样求最小循环节? 如abcabcabc
next数组为:
a | b | c | a | b | c | a | b | c | |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
-1 | 0 | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
next[len]是一个很特殊的值,它表示整个字符串前后缀相同的最大长度
如上栗子,next[len]=6
说明 字符串中 a[0]-a[5] 与 a[3]-a[8]是完全相同的
也就是说 a[0]-a[2]与 a[3]-a[5]是完全相同的,a[3]-a[5] 与 a[6]-a[8]是完全相同的,
也就是说该字符串可以由 a[0]-a[2]循环3次组成
所以只要tlen%(tlen-next[tlen])==0&&next[tlen]!=0 字符串就可以由长度比它小的子串组成
否则循环节为它本身
while(~scanf("%s",t)) { tlen=strlen(t); getNext(); if(tlen%(tlen-next[tlen])==0&&next[tlen]!=0)printf("%d\n",tlen-next[tlen]); else printf("%d\n",tlen); }
3.kmp求模式串第一次出现的位置
int kmp_Index() { int i=0,j=0; getNext(); while(i<slen&&j<tlen) { if(j==-1||s[i]==t[j]) { i++; j++; } else j=next[j]; } if(j==tlen)return i-tlen; else return -1; }
4.kmp求模式串在匹配串中出现的次数(有可重叠和不可重叠之分)
int kmp_Count() { int ans=0; int i,j=0; if(slen==1&&tlen==1) { if(s[0]==t[0])return 1; else return 0; } getNext(); for(i=0;i<slen;i++) { while(j>0&&s[i]!=t[j])j=next[j]; if(s[i]==t[j])j++; if(j==tlen) { ans++; j=0; //如果子串可以重叠j=next[j]; } } return ans; }
烤(k)馍(m)片(p)完整模板:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #define N 1000010 using namespace std; int next[N]; char s[N],t[N]; int slen,tlen; void getNext() { int j,k; j=0;k=-1;next[0]=-1; while(j<tlen) { if(k==-1||t[j]==t[k])next[++j]=++k; else k=next[k]; } } //返回模式串t在主串s中首次出现的位置 int kmp_Index() { int i=0,j=0; getNext(); while(i<slen&&j<tlen) { if(j==-1||s[i]==t[j]) { i++; j++; } else j=next[j]; } if(j==tlen)return i-tlen; else return -1; } //返回模式串t在主串s中出现的次数 int kmp_Count() { int ans=0; int i,j=0; if(slen==1&&tlen==1) { if(s[0]==t[0])return 1; else return 0; } getNext(); for(i=0;i<slen;i++) { // printf("***%d %d\n",i,j); while(j>0&&s[i]!=t[j])j=next[j]; if(s[i]==t[j])j++; if(j==tlen) { ans++; j=0; //如果子串可以重叠j=next[j]; } } return ans; } int main() { //用next数组求循环节的长度 while(~scanf("%s",t)) { tlen=strlen(t); getNext(); // for(int i=0;i<=tlen;i++)printf("%d %d\n",i,next[i]); if(tlen%(tlen-next[tlen])==0&&next[tlen]!=0)printf("%d\n",tlen-next[tlen]); else printf("%d\n",tlen); } /* //kmp模式匹配 while(~scanf("%s%s",s,t)) { slen=strlen(s); tlen=strlen(t); // printf("%d\n",kmp_Index()); printf("%d\n",kmp_Count()); // for(int i=0;i<=tlen;i++)printf("%d %d\n",i,next[i]); } */ return 0; }
标签:
原文地址:http://www.cnblogs.com/kylehz/p/4392945.html