Update:我这口胡的是什么啊=-=我都看不懂了 算了算了给个链接这个讲的特好
来讲讲KMP
First......读入两字符串后 将将被搜索的关键字 先进行自我配对
长度1..2..3......len(串) - 1 意为 字符串前x个字符的 前缀 与 后缀 相等的最大长度
此处注意 前缀 和 后缀 各自的长度 似乎不能等于原串的样子=-=
每个长度都要保存下来 可存到某一数组里 通常用 next fail 等名称定义 依据是他的作用
Fa♂Q : 这个解释模模糊糊看起来怪怪的存长度的数组...... 有什么用
Ans~ : 之后查找长度的时候会用到~
作用是 当两个字符串比着比着 突然对不上了的时候
他就可以挺♂身而出 给将被搜索的关键字跳回去 至于总串嘛他太懒了懒得改
那关键字怎么改呢
Second...说起来是改 实际上是跳
首先 你可以通过存两个字符串正在比的地方(用int一类 或 指针) 找到 关键字比到哪儿了
For instance 以 char[1] 开始 设总串指针为 i 关键字指针为 j
关键字比到第666位了 然后第667位不一样 则 i = 666
先设该666位字符是abcab......abcabd 红色的是第667个
此时总串比到2333位 是......abcabcabc 红色的是第2334个 j = 2333
哈 通过next[667] = 5 你找到了关键字前666位的前缀和后缀 正是abcab
因此直接跳把关键字的指针 跳到 2 此时 i = 2
此时比较关键字第 3 位 c 和 总串第2334位 c 相等
LOLOLOL 我们就可以开心地比下去啦
如果此时两字符还不同 通过 next 数组 找到 next[i] 继续跳 直到跳到头 i = 0 就相当于重新匹配了=-= 从零开始的搜索......
Useless notes:
用 string 读的字符串 和 下标0开头的 char 类型的 KMP 部分几乎是一样的
然后 下标1 开头1 的 char 又 有所改变=-=
为防止思路混乱 在此将三篇都记下来(前两者转换只用改改 类型 和 串长求法 而已)
其中1下标char跑得非常非常慢,但是下标换成0就没事了 原因不详 实在是太毒瘤了
模板题 洛谷P3375
Tip:因为懒得打子程序直接堆一起啦~
sky_killed(被天杀的) char[1] 开头——
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAX = 1 << 21;
char i[MAX],j[MAX];
int next[MAX];
int main()
{
int b;
scanf("%s%s",i + 1,j + 1);
int li = strlen(i + 1);
int lj = strlen(j + 1);
for (int a = 2; a <= lj; a++)//建立next数组
{
while (b && j[a] != j[b + 1]) b = next[b];
if (j[a] == j[b + 1]) ++b;
next[a] = b;
}
b = 0;
for (int a = 1; a <= li; a++)//开始匹配
{
while (b > 0 && i[a] != j[b + 1]) b = next[b];
if (i[a] == j[b + 1]) ++b;
if (b == lj) printf("%d\n",a - b + 1),b = next[b];
}
for (int a = 1; a <= strlen(j + 1); a++) printf("%d ",next[a]);//烦人的题目要求输出next数组=-=
return 0;
}
总共 T 三个点~
normal char[0] 开头——
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAX = 1 << 21;
char i[MAX],j[MAX];
int next[MAX];
int main()
{
int b;
scanf("%s%s",i,j);
int li = strlen(i);
int lj = strlen(j);
for (int a = 1; a < lj; a++)//建立next数组
{
while (b && j[a] != j[b]) b = next[b];
if (j[a] == j[b]) ++b;
next[a + 1] = b;
}
b = 0;
for (int a = 0; a < li; a++)//开始匹配
{
while (b && i[a] != j[b]) b = next[b];
if (i[a] == j[b]) ++b;
if (b == lj) printf("%d\n",a - b + 2),b = next[b];
}
for (int a = 1; a <= lj; a++) printf("%d ",next[a]);
return 0;
}
总 300ms~
Useful string ——
Tip:AC自动机要用string哦 char慢死=-=
好吧也可能是我自己的问题(就是你自己的问题不要推卸责任)
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int next[1 << 21];
int main()
{
int b;
string i,j;
cin >> i;
cin >> j;
int li = i.size();
int lj = j.size();
for (int a = 1; a < lj; a++)//建立next数组
{
while (b && j[a] != j[b]) b = next[b];
if (j[a] == j[b]) ++b;
next[a + 1] = b;
}
b = 0;
for (int a = 0; a < li; a++)//开始匹配
{
while (b && i[a] != j[b]) b = next[b];
if (i[a] == j[b]) ++b;
if (b == lj) printf("%d\n",a - b + 2),b = next[b];
}
for (int a = 1; a <= lj; a++) printf("%d ",next[a]);
return 0;
}
总 616ms~ 慢了点呢