时间复杂度:o(m+n)
空间复杂度:o(n)
m:主串
n:子串
作用:
在一个已知的字符串中查找子串的位置。
思路:
假设有主串z和模板串(子串)m
主串:A B B A B B A A B A A
子串:A B B A B A A
下标:1 2 3 4 5 6 7
由上图可知,主串与子串在下标为6的位置不匹配,我们此时需要做的是找出子串与主串的最长相等的前缀与后缀。如:
主串:A B B A B B A A B A A
子串:A B B A B A A
下标:1 2 3 4 5 6 7
子串中的下标为6的字符A,此时开一个next数组存储当前A的下标,为next[6],在A字符前面找最大的前缀与后缀(注意:此时不能找子串本身作为最长前缀,这没有意义)。
如上图,
主串:A B B A B B A A B A A
子串:A B B A B A A (AB称为子串的公共前后缀)
下标:1 2 3 4 5 6 7
A的最大前(后)缀为AB,如图
,
A B B A B A
此时移动子串使得下标为 3的子串前缀与主串后缀对齐:
主串:A B B A B B A B A A
子串 A B B A B A A (AB称为子串的公共前后缀)//此时是将子串的前缀 ^ // 移动到后缀的位置
下标: 1 2 3 4 5 6 7
依次类推,直到子串与主串匹配成功时,匹配结束。
核心代码:
// s[]是主串,p[]是子串,n是s的长度,m是p的长度
//求子串的Next数组:
for (int i = 2, j = 0; i <= m; i ++ )
{
while (j && p[i] != p[j + 1])//不匹配
j = ne[j];
if (p[i] == p[j + 1])//匹配
j ++ ;//继续向后遍历
ne[i] = j;
}
// 匹配过程
for (int i = 1, j = 0; i <= n; i ++ )
{
while (j && s[i] != p[j + 1])
j = ne[j];
if (s[i] == p[j + 1])
j ++ ;
if (j == m)
{
j = ne[j];
// 匹配成功后的逻辑
}
}
代码参考
y总
最后要说的就是一定要理解过程,不要死记代码模板。
觉得好的点个小赞,有错误请指出,谢谢
必须赞!大佬,我最近也在学KMP呢,感觉next数组有点困难(去看看蓝皮书hh)
hh理解过程就好了,我刚学的时候也觉得有点难