本文已参与「新人创作礼」活动,一起开启掘金创作之路。
以图中的例子来说,在 i 处失配,那么主字符串和模式字符串的前边6位就是相同的。又因为模式字符串的前6位,它的前4位前缀和后4位后缀是相同的,所以我们推知主字符串i之前的4位和模式字符串开头的4位是相同的。就是图中的灰色部分。那这部分就不用再比较了。
s[ ]是模式串,即比较长的字符串
#include <iostream>
using namespace std;
const int N = 100010,M = 1000010;
int n,m;
char p[N],s[M]; // p是要匹配的字符串
int ne[N];
int main()
{
ios::sync_with_stdio(false);
cin >> n >> p+1 >> m >> s+1;
// 求next数组
for(int i = 2,j = 0; i <= n; i++)
{
while(j && p[i] != p[j+1]) j = ne[j];
if(p[i] == p[j+1]) j++;
ne[i] = j;
}
// kmp匹配过程
for(int i = 1,j = 0; i <= m; i++)
{
while(j && s[i] != p[j+1]) j = ne[j];
if(s[i] == p[j+1]) j++;
if(j == n)
{
// 匹配成功
cout << i - n << ' ';
j = ne[j];
}
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
void prefix_table(char pattern[], int prefix[], int n)
{
prefix[0] = 0;
int len = 0;
int i = 1;
while(i < n)
{
if(pattern[i]==pattern[len])
{
len++;
prefix[i] = len;
i++;
}
else
{
if(len > 0)
{
len = prefix[len - 1];
}
else
{
prefix[i] = 0;
i++;
}
}
}
}
void prefix_move(int prefix[], int n)
{
for(int i = n - 1; i > 0; i--)
{
prefix[i] = prefix[i-1];
}
prefix[0] = -1;
}
void kmp_search(char text[], char pattern[])
{
int n = strlen(pattern);
int m = strlen(text);
int *prefix = (int *)malloc(sizeof(int) * n);
prefix_table(pattern, prefix, n);
prefix_move(prefix,n);
int i = 0, j = 0;
while(i < m)
{
if(j == n-1 && text[i] == pattern[j])
{
printf("%d\n",i-j+1);
j = prefix[j];
}
if(text[i]==pattern[j]) i++, j++;
else
{
j = prefix[j];
if(j == -1) i++, j++;
}
}
prefix_table(pattern, prefix, n);
for(i = 0; i < n; i++)
{
printf("%d ",prefix[i]);
}
//text[i] , len[text] = m
//pattern[j] , len[pattern] = n
}
int main()
{
char text[1000010];
char pattern[1000010]; //要搜索的内容
cin >> text;
cin >> pattern;
kmp_search(text, pattern);
return 0;
}