网上有很多kmp算法的博客,看了好久都没有弄懂,于是就自己写一篇。
首先我们需要明确几个定义:
前缀:字符串前面的一段
后缀:字符串后面的一段
kmp算法思想:寻找一个字符串的,前缀与后缀的最大匹配,该前缀后缀不能为它自身。
在朴素字符串匹配中,若某一点不匹配,则需要从头开始,这中间会做了有很多不必要的工作。
我们找到已匹配字符串段的后缀的最大前缀匹配,再将该前缀作为已匹配字符串往后遍历。
由于找到的是后缀的最大前缀匹配,因此可以保证不会有遗漏。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define maxn 1002000
#define maxm 1002000
int next[maxm];
void findnext(char s[]) {//寻找当前的后缀的最大的前缀匹配
int lens = strlen(s), i = 1, k = 0;//i=0时无匹配
while (i != lens) {
if (s[i] == s[k])next[i] = k + 1, ++k, ++i;//若匹配,则最大匹配长度为k+1
else if (s[i] != s[k]) {//不匹配
if (k == 0)i++;//说明不存在
else k = next[k - 1];//回退,已匹配的字符串的最大前缀和后缀的匹配
}
}
}
int main() {
char s1[maxn], s2[maxm];
int i, j, k, lens1, lens2;
scanf("%s", s1);
scanf("%s", s2);
findnext(s2);
lens1 = strlen(s1), lens2 = strlen(s2);
for (i = 0, j = 0; i < lens1; i++) {//字符串匹配,输出所有匹配位置
if (s1[i] == s2[j]) {
if (j == lens2 - 1) {//匹配了后再次寻找最大前缀
printf("%d\n", i - j + 1);
j = next[j];
}
else j++;
}
else {//不匹配
if (j == 0)continue;
else j = next[j - 1], i--;
}
}
for (i = 0; i < lens2; i++)printf("%d ", next[i]);
}
学完了自己也试试题目吧
P3375 【模板】KMP字符串匹配