拓展KMP算法
对于某些题目,偶尔会出现KMP算法超时的情况,这个时候就要用到EKMP算法了
EKMP主要求两个数组
next数组和extend数组
对于两个字符串,他们的next数组和extend数组为
如给你一个T字符串,求s串在T中的位置
T : a a a b c a
ex: 2 4 1 0 0 1
S : a a b c
ne: 4 1 0 0
明显可以看出,next数组的含义为 next[ i ]表示s串从第i个字符开始,与s串匹配的个数
ex数组的含义是 ex[ i ]表示从T串第i个字符开始,与S串匹配的个数
EKMP算法的核心思想:
对于匹配过程中 如果s[0,5]和T[0,5]匹配成功了(表示字符串s和T从s[0],T[0]到S[5],T[5]都匹配成功)
那么 s[1,5]和T[1,5]必定也匹配成功
那么这部分在下次运用的时候就不必再进行匹配了
关键就是如何利用这部分
用a记录匹配成功的开始地方
p记录匹配成功的结束地方(即最远匹配的距离)
p-a+1必定小于等于s串的长度
next[i-a]表示T[i]往后匹配S串能匹配的长度
下面代码
#include<iostream>
#include<string>
#include<string.h>
#include<stdio.h>
using namespace std;
char T[1000000],S[100000];
/* 求解T中next[],注释参考GetExtend() */
void GetNext(char *T, int next[])
{
int t_len = strlen(T);
next[0] = t_len;
int a;
int p;
for (int i = 1, j = -1; i < t_len; i++, j--)
{
if (j < 0 || i + next[i - a] >= p)
{
if (j < 0)
p = i, j = 0;
while (p < t_len&&T[p] == T[j])
{
p++, j++;
}
next[i] = j;
a = i;
}
else
next[i] = next[i - a];
}
}
/* 求解extend[] */
void GetExtend(char *S, char *T, int extend[], int next[])
{
GetNext(T, next); //得到next
int a;
int p; //记录匹配成功的字符的最远位置p,及起始位置a
int s_len = strlen(S);
int t_len = strlen(T);
for (int i = 0, j = -1; i < s_len; i++, j--) //j即等于p与i的距离,其作用是判断i是否大于p(如果j<0,则i大于p)
{
if (j < 0 || i + next[i - a] >= p) //j<0表示计算的字符已经到最远匹配位置了
{
//next[i-a]表示最多还能匹配几位,如果超过P了,那么不能取next[i-a]了
if (j < 0)//如果i大于P
{
p = i, j = 0; //如果i大于p
}
while (p < s_len&&j < t_len&&S[p] == T[j])//如果可以匹配,继续匹配
{
p++, j++;
}
extend[i] = j;
a = i;
}
else
extend[i] = next[i - a];
}
}
int main()
{
int next[100] = { 0 };
int extend[100] = { 0 };
scanf("%s%s",T,S);
GetExtend(S, T, extend, next);
//打印next和extend
cout << "next: " << endl;
for (int i = 0; i < strlen(T); i++)
cout << next[i] << " ";
cout << "\nextend: " << endl;
for (int i = 0; i < strlen(S); i++)
cout << extend[i] << " ";
cout << endl;
return 0;
}