前缀表
前缀 就是包含首字母的字符串如abcdef他的前缀就有a 、ab、abc、abcd、abcde。这些都是他的前缀,同理后缀亦是如此。
前缀表则是用来记录最长公共前后缀的长度。
就以一个字符串:aabaaf为例子
字符串的起始数字为1
从a开始求a的前缀和后缀的最大公共长度为0。(前后缀都为空,因为前/后缀不包含末尾/首)
下一个前缀为a 后缀为a 长度就为1。
aab的前缀和后缀无公共长度则为0,以此类推可得出前缀表
a | a | b | a | a | f |
1 | 2 | 3 | 4 | 5 | 6 |
0 | 1 | 0 | 1 | 2 | 0 |
下面是代码的分析过程:
我们来构造一个next数组来存放前缀表
函数的参数有两个,一个取是模式串s,另一个就是数组next。
1初始化,为了判断前后缀是否有公共字串,所以设 i 作为后缀的尾字母,j 为前缀的尾字母。
int j = -1;
next[0] = j;
设 j = -1;
next[i] 表示 i(包括i)之前最长相等的前后缀长度(其实就是j)
所以初始化next[0] = j 。
2开始判断前后缀不同的情况
j初始化为-1,那么i就从1开始,进行s[i] 与 s[j+1]的比较。
如果 s[i] 与 s[j+1]不相同,也就是遇到 前后缀末尾不相同的情况,就要向前回退。
那么 s[i] 与 s[j+1] 不相同,就要找 j+1前一个元素在next数组里的值(就是next[j])。
while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
j = next[j]; // 向前回退
}
3处理前后缀相同的情况
如果 s[i] 与 s[j + 1] 相同,那么就同时向后移动i 和j 说明找到了相同的前后缀,同时还要将j(前缀的长度)赋给next[i], 因为next[i]要记录相同前后缀的长度。
if (s[i] == s[j + 1]) { // 找到相同的前后缀
j++;
}
则整体的next数组如下。
void getNext(int* next, const string& s){
int j = -1;
next[0] = j;
for(int i = 1; i < s.size(); i++) { // 注意i从1开始
while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
j = next[j]; // 向前回退
}
if (s[i] == s[j + 1]) { // 找到相同的前后缀
j++;
}
next[i] = j; // 将j(前缀的长度)赋给next[i]
}
}