学习了一下浙大陈越姥姥讲的KMP算法,顺便记录了一下,下面是课程链接
传送门
在学习的过程中一直有一个疑点,就是求match[j]失配的时候,为什么要回溯到match[j-1],而不是pattern[j-1]呢?后来想了一下,这个过程跟KMP还是很像的,中间不存在比match[j-1]这个位置还合适的回溯点了,如果有,那么match[j-1]的位置一定在那个回溯点,反证法得知这个结论是正确的。
#include<bits/stdc++.h>
using namespace std;
typedef int Position;
#define NotFound -1
char text[20], pattern[20];
Position KMP(char *text, char *pattern);
void BuildMatch(char *pattern, int *match);
int main()
{
cin>>text;
cin>>pattern;
Position t = KMP(text,pattern);
if(t == NotFound)
{
cout << "NotFound" << endl;
}else{
cout << text + t << endl;
}
cout<<t;
return 0;
}
Position KMP(char *text,char *pattern)
{
//获取string的长度
int n = strlen(text);
//获取pattern串的长度
int m = strlen(pattern);
//操纵string,pattern,pattern的回溯数组
int s, p, *match;
//模式串的长度
match = (int *)malloc(sizeof(int) * m);
BuildMatch(pattern, match);
//初始化
s = p = 0;
while (s<n && p<m)
{
if(text[s]==pattern[p])
s++, p++;
//不等就回溯
else if (p>0)
p = match[p - 1] + 1;
//p==0,无处可退就s++;
else
s++;
}
return (p == m) ? (s - m) : NotFound;
}
void BuildMatch(char *pattern,int *match)
{
int m = strlen(pattern);
//第一位没有子串
match[0] = -1;
//其实这里可以把模式串当做主串
//不回溯,j一直往下走
for (int j = 1; j < m;j++)
{
int i = match[j - 1];
while (i>0 && pattern[i+1]!=pattern[j])
{
i = match[i];
}
if(pattern[i+1]==pattern[j])
{
//回溯完如果配上了
match[j] = i + 1;
}
//如果没配上
else{
match[j] = -1;
}
}
}
2023.2.12更新:
简洁版写法:
#include<iostream>
using namespace std;
const int N = 100010, M = 1000010;
char s[M], p[N];
int ne[1000010];//注意范围随s[M]
int n, m;
int main()
{
cin >> n >> p + 1 >> m >> s + 1; // 模式串p的长度
//求next数组,表示匹配长度,用本串求
for (int i = 2, j = 0; i <= m; i++)
{
while (j&&p[i]!=p[j+1])
j = ne[j];
if(p[i]==p[j+1])
j++;
ne[i] = j;//记录一下
}
//匹配过程
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)
{
//下标从0开始,如果下标从1开始则输出i-j+1
cout << i - j<<" ";
j=ne[j];//主串中可能有多个子串与模式串匹配
}
}
return 0;
}