1.求next数组
1.1 定义
- 什么是最长相等前后缀长度?
字符串 ab
的最长相等前后缀为空集,长度为0
字符串 aba
的最长相等前后缀为a
,长度为1
字符串 aaa
的最长相等前后缀为aa
,长度为2
字符串 ababa
的最长相等前后缀为aba
,长度为3
-
next数组是什么?
next[i]
:前i-1
个字符的 最长相等前后缀长度 + 1str: a b a b a next: 0 1 1 2 3
如
next[3] = f("aba") + 1 = 1 + 1 = 2
str: (a b a) b a next: 0 1 1 ? ↑
1.2 next数组的两种情况
- 本质是自己和自己匹配
- 初始化:
i = 1
表示next数组位置/主串位置。j = 0
表示子串位置。 - j相当于已匹配个数。
下面以ababaaab
作为例子,计算next数组
初始位置
a b a b a a a b
a b a b a a a b
↑
(i = 1; j = 0)
情况一:字符相同
0 1 1
a b a b a a a b
a b a b a a a b
↑
(i = 3; j = 1)
则:
1. 先将结果记下来,对于当前位置,已经匹配了j=1个,即aba的部分的最长相等前后缀为1,根据next数组定义,则next[i]=j+1
2. i++; j++; 匹配下一位
结果:
0 1 1 2
a b a b a a a b
a b a b a a a b
↑
(i = 4; j = 2)
情况二:字符不同
0 1 1 2 3
a b a b a a a b
a b a b a a a b
↑
(i = 5; j = 3)
则:
1.先将结果记下来,这部分同情况一,next[i] = j + 1
2.循环判断,如果不匹配,j = next[i] - 1
直到j == -1 或成功匹配 跳出循环
3. i++; j++; 匹配下一位
j = next[i] - 1 解析:
字符串在"abab"的"b"处失配,通过next[3]("b"的位置为3)我们得知,前面"aba"部分的最长相等前后缀为 next[3] - 1 = 1。所以接下来不需要重新开始匹配,可以从开头跳过1个字符。综上,即j = next[i] - 1。
跳出循环解析:
- 如果j一直到开头都没有匹配到,因为next[0] - 1 = 0 - 1 = -1 的原因,跳出循环后进行j++,下一次相当于重头匹配。
- 如果j匹配到了,此时相当于情况1。
代码
public int[] getNext(String s)
{
int[] next = new int[s.length()];
int i = 1;
int j = 0;
next[0] = 0; // 定义
while (i < s.length()) {
next[i] = j + 1; // 首先记录当前结果
// 如果不匹配,则找到已匹配的个数(j),
while (j >= 0 && s.charAt(i) != s.charAt(j)) {
j = next[j] - 1;
}
// 二者指针右移,继续下一位匹配
j++;
i++;
}
return next;
}
2. kmp算法
public int kmp(String str, String substr)
{
// 从0开始匹配
int i = 0;
int j = 0;
// 获取子串的next数组
int[] next = getNext(substr);
while (i < str.length() && j < substr.length()) {
// 匹配下一位
if (j == -1 || str.charAt(i) == substr.charAt(j)) {
i++;
j++;
}
else
// 找到合适的位置(已匹配个数)
j = next[j] - 1;
}
// 成功匹配,返回下标
if (j == substr.length()) {
return i - substr.length();
}
// 失败匹配
return -1;
}
标签:int,后缀,匹配,substr,++,next,简易,算法,kmp
From: https://www.cnblogs.com/aminor/p/16794291.html