KMP随笔

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就没事了

            应该是循环里多个 a + 1, b + 1 的原因 在此注意一下

模板们 + 题目 洛谷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~ 慢了点呢

猜你喜欢

转载自blog.csdn.net/frocean/article/details/80844940
kmp
今日推荐