什么是最长相等前后缀?
前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串
后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串
其中黄色部分是前缀
绿色部分是后缀
这个字符串的最长相等前后缀是3
前缀表
前缀表(next数组):记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。
!!如何求前缀表
对第一个字符 其最长相等前后缀一定是0
next[0] = 0;
用for循环使指针i逐个后移,计算next[i]
for(int i = 1, j = 0; i<s.size(); i++) {
//计算过程
}
指针i指向的是后缀的末尾
指针j指向的是与该后缀相同的前缀的末尾即next[i],或者第一个字符(没有相同的前后缀,next[i] = 0)
-
上一轮找到相等的先后缀后,i和j都后移,当后移之后,前后缀末尾仍然相同时,说明此时最长相等前后缀 = 前一轮最长相等前后缀+1`
-
当后移后前后缀末尾不同时,即:
说明此时 最长相等前后缀长度小于j
,需要将j
前移,直至找到一个更小的最长相等前后缀next[i]
。
由于是在上一轮找到相等前后缀的基础上后移得到的i
和j
,因此前j-1
个字符和i
前面j-1
个字符应该是一样的(灰色区域)
由于i
前面的前缀表是已知的,即知道next[j-1] = m
那么
next[j-1] = m
意味着什么呢?
意味着在前j-1
个字符中,前m
个和后m
个字符形成的前后缀是一样的(浅蓝色区域)
又 因为 前j-1
个字符和i
前面j-1
个字符是一样的,因此最前面m
个字符和i前面m
个字符形成的前后缀是一样的,将j
移动到next[j-1]
处
比较s[j]
是否等于s[i]
,若相等则找到了最长相等前后缀
若仍然不等,则继续前移,直到前移到开头元素,说明没有相等的前后缀
完整代码为:
void getNext(int* next, const string& s) {
next[0] = 0;
for(int i = 1, j = 0; i<s.size(); i++) {
while (s[i] != s[j] && j > 0) {
j = next[j - 1];
}
if(s[i] == s[j]) {
next[i] = j + 1;
j++;
}
else if( j == 0) {
next[i] = 0;
}
}
}