写在前面:
模式串下标从0开始,next数组和nextval数组从-1开始;
例如:
abcabd aaaaaaab
next -100012 -10123456
nextval -100002 -10000006
代码:
普通KMP (时间复杂度 O(n + m))
#include <stdio.h>
#include <string.h>
#define N 100
void Get_Next(char t[], int len);
int KMP(char s[], char t[], int lens, int lent);
int next[N];
int main()
{
char s[N], t[N];
scanf("%s%s", s, t);
Get_Next(t, strlen(t));
int start = KMP(s, t, strlen(s), strlen(t));
printf("%d\n", start);
return 0;
}
int KMP(char s[], char t[], int lens, int lent)
{
int i = 0, j = 0;
while(i < lens && j < lent){
if(j == 0 || s[i] == t[j]){ //虽然next是从-1开始,但这儿j最小为0
i ++;
j ++;
}
else{
j = next[j];
}
}
if(j == lent) return i - lent;
else return -1;
}
void Get_Next(char t[], int len)
{
int i = 0, j = -1;
next[0] = -1;
while(i < len){
if(j == -1 || t[i] == t[j]){
/* j == -1 表示当前next[i]保持初始值(0)不变,然后next[i+1] = 0;
next[i] = j 指 t[i-j+1...i-1] == t[0...j]; */
i ++;
j ++;
next[i] = j;
}
else
j = next[j];
}
}
优化的KMP (时间复杂度 O(m))
#include <stdio.h>
#include <string.h>
#define N 100
void Get_NextVal(char t[], int len);
int KMP(char s[], char t[], int lens, int lent);
int nextval[N];
int main()
{
char s[N], t[N];
scanf("%s%s", s, t);
Get_NextVal(t, strlen(t));
int start = KMP(s, t, strlen(s), strlen(t));
printf("%d\n", start);
return 0;
}
int KMP(char s[], char t[], int lens, int lent)
{
int i = 0, j = 0;
while(i < lens && j < lent){
if(j == 0 || s[i] == t[j]){
i ++;
j ++;
}
else{
j = nextval[j];
}
}
if(j == lent) return i - lent;
else return -1;
}
void Get_NextVal(char t[], int len)
{
int i = 0, j = -1;
nextval[0] = -1;
while(i < len){
if(j == -1 || t[i] == t[j]){
i ++;
j ++;
if(t[i] != t[j]) nextval[i] = j;
else nextval[i] = nextval[j];
}
else
j = nextval[j];
}
}