声明
本文资料参考acwing算法基础课
地址:https://www.acwing.com
概述
- 解决问题:字符串匹配
- 平均时间复杂度为O(n)
- 注意字符串从1开始
模板记忆
这个模板分为两个部分:
- next:更新next数组,每次循环:迭代移动j,匹配成功j ++ , ne[i] = j;
- 匹配:字符串匹配,每次循环:迭代移动j,匹配成功j++,到达结尾j = ne[j]
注意的点:
next和匹配部分的区别
- next的i从2开始,匹配的i从1开始
- next的i指示p的下标,匹配指示s下标
- next最后一步是更新next,匹配是匹配成功并且修改j = ne[j]
模板代码
// 更新next数组,i表示准备更新的next下标(即将被比较的下标),j表示已知首部重合区间最后一位的下标(被比较的前一位下标)
for (int i = 2, j = 0; i <= n; i ++) // i从2开始,默认ne[1]为0,j从0开始
{
while (j && p[i] != p[j + 1]) j = ne[j]; // 当j为0的时候j不能继续迭代了,当j + 1和i匹配不成功的时候继续迭代
if (p[i] == p[j + 1]) j ++ ; // 如果是匹配成功停下的,移动j+1,这时候j表示算上i的区间最大匹配前后缀,如果是j为0停下的,next就是0
ne[i] = j; // 更新i的next
}
// 字符串匹配,i表示准备匹配的字符下标,j表示已知重合区间的最后一位
for (int i = 1, j = 0; i <= m; i ++ ) // i从1开始
{
while (j && s[i] != p[j + 1]) j = ne[j]; // 当j为0的时候j不能继续迭代了,当j + 1和i匹配不成功的时候继续迭代
if (s[i] == p[j + 1]) j ++ ; // 如果是匹配成功停下的,移动j+1,这时候j表示算上i的区间最大匹配前后缀,如果是j为0停下的,就应该移动i了
if (j == n)
{
cout << i - n << ' ';
j = ne[j]; // 匹配成功移动一下j就相当于匹配成功后模式串要前移的尽可能小,需要移到ne[j]
}
}