分析:
(1)对于模式串的位置j,考察Patternj-1=P0P1···Pj-2Pj-1,查找字符串Patternj-1 的最大相等k前缀和k后缀 ,
注:计算
n
e
x
t
[
j
]
next[j]
next[j]时,考察的字符串是模式串的前j-1个字符,与
P
a
t
t
e
r
n
[
j
]
Pattern[j]
Pattern[j]无关。
(2)即:查找满足条件的最大的
k
k
k,使得
P
0
P
1
⋯
P
k
−
2
P
k
−
1
=
P
j
−
k
P
j
−
k
+
1
⋯
P
j
−
2
P
j
−
1
P_0P_1\cdots P_{k-2}P_{k-1}=P_{j-k}P_{j-k+1}\cdots P_{j-2}P_{j-1}
P0P1⋯Pk−2Pk−1=Pj−kPj−k+1⋯Pj−2Pj−1。
求模式串的next:
模式串 | a | b | a | a | b | c | a | b | a |
---|---|---|---|---|---|---|---|---|---|
n e x t \bm{next} next | -1 | 0 | 0 | 1 | 1 | 2 | 0 | 1 | 2 |
如:j=5时,考察字符串“ a b a a b abaab abaab”的最大相等k前缀和k后缀。
前缀串 | 后缀串 |
---|---|
a \bm{a} a | b \bm{b} b |
a b \bm{ab} ab | a b \bm{ab} ab |
a b a \bm{aba} aba | a a b \bm{aab} aab |
a b a a \bm{abaa} abaa | b a a b \bm{baab} baab |
a b a a b \bm{abaab} abaab | a b a a b \bm{abaab} abaab |
next的递推关系:
(1)对于模式串的位置j,已知next[j] = k,即:P0P1···Pk-2Pk-1=Pj-kPj-k+1···Pj-2Pj-1
(2)则对于模式串的位置j+1,考察Pj:
(3)若P[k] == P[j],则有next[j+1] = next[j]+1
(4)若P[k]≠P[j],记h=next[k],如果P[h]=P[j],则next[j+1]=h+1,否则重复此过程。
计算next数组:
void getNext(char *p,int next[])
{
int Len = strlen(p);
next[0] = -1;
int j = 0;
int k =-1;
while(j < Len-1)
{
//注:k = -1表示未找到k前缀和k后缀相等
if( k == -1 || p[j] == p[k])
{
j++;
k++;
next[j]=k;
}
else
{
k = next[k];
}
}
}
参数不同的情况:
vector<int> getNext(string str)
{
int Len = str.length();
vector<int> next;
next.push_back(-1);
int j = 0;
int k =-1;
while(j < Len-1)
{
//注:k = -1表示未找到k前缀和k后缀相等
if( k == -1 || p[j] == p[k])
{
j++;
k++;
next.push_back(k);
}
else
{
k = next[k];
}
}
return next;
}
KMP算法:
int KMP(string target,string pattern)
{
if(pattern.empty())
return 0;
vector<int> next;
next = getNext(pattern);//此处调用第二种情况的next数组方法
int n = target.length();
int m = pattern.length();
int i = 0;
int j = 0;
while(i < n && j < m)
{
if(j == -1 || target[i] == pattern[j])
{
i++;
j++;
}
else
{
j = next[j];
}
}
if(j == m)
return i-j;
return -1;
}