KMP 算法 笔记

KMP 包含一个PMT表。

我们把 待匹配的文字称为 模式字符串.

前缀 : “aba” 前缀为 除去 最后一个 字符 “a” 所 形成 的集合。 {“a”,“ab”}
后缀 : “aba” 后缀 为 除去 最前的一个字符串 “a” 所形成的集合 {“a”,“ba”}

它们 之间的 交集为 {“a”} ,长度为 1,那么 在 PMT表 中 a 对应 1.
在这里插入图片描述

模式字符串 issip 在 某一个 地方 出现 不匹配,那么 至少 在 前 j -1 个字符是匹配的.
在这里插入图片描述
如果 是普通的 做法,如果我们 碰到 不匹配的 字符就把 j 指针置 为 0,这样就错过了 可能能匹配的字符串,

之所以发生这样的情况 是因为 受到 上一次匹配的影响,而导致 错过了 。

在 上上张图中 ,假设 我们 错过了 匹配 隐含的意思是,在 前 j -1 个数中,和 i - j 个数中 ,必然 会存在 公共的部分。

对吧 要匹配 那么 最基本的 前 n 个数 要一样吧 。

比如 a 和 ab 能匹配是因为 都是 以 a 开头的,那么 我们 就可以 证明 像 abc 不可能 出现上面错过的情况,为什么呢?
假设 有个字符串 m 和你匹配 , 前几个 都一样 但是唯独 c 不一样,那么 你想想 如果 出现上面 那种情况的话 一位 这 在已匹配的 ab 里面 还要 有一个 a ,因为 匹配 是以 a 开头的。如果 你因为 匹配 abc 而错过了 可能成功匹配的字符,那么 必然 在 匹配ab 的时候 还有一个 a 对应。
说的简单点 就是 你要匹配一个字符串 至少 开头 要一样吧,那么 如果 一个没有一个重复数字的字符串。 你怎么 可能再次 匹配到呢?
在这里插入图片描述

那么我们再 举个例子 “aba” 注意到 没有 这个 字符串 a 出现了 两次 。

举个例子 :
abc
ababc

在这里插入图片描述当我们 的 a 和 c 作比较的时候 不相等,但是 匹配字符串 是以 a 开头的 那么 我们不希望 错过可能的 下一次匹配机遇,那我们 就 尝试 把 j 的索引 改成 0 再次开始 匹配。

再 举个例子:
在这里插入图片描述

a b a 集合
前缀 {a,ab}
后缀 {ba,a}
交集 {a}

在这里插入图片描述

在 j = 3 ,出现不匹配 ,而且 a 出现了 2次 那么 那么第二次a出现的位置 正好可以 当做 另一次 匹配的 开始。

在这里插入图片描述

前面 aba 的 前后缀的交集 把 a 我们可以把 a 看做一个模式
那么 abab 的 前后缀的交集 ab 就是一个模式

在这里插入图片描述
next 就是 pmt 表 前面 第0 为 push -1 然后 最后一位 remove。

计算 pmt 表 rust 代码

pub fn pmt(needle: String) ->Vec<usize>{
    let mut tmpvec = Vec::with_capacity(needle.len());
    tmpvec.push(0);
    let mut j = 0;
    let mut i = 1;
    for _ in 1.. needle.len() {
        if needle.as_bytes()[i] != needle.as_bytes()[j] {
            while needle.as_bytes()[i] != needle.as_bytes()[j] && j >= 1 {
                    j = tmpvec[j-1];
            }
        }
        if needle.as_bytes()[i] == needle.as_bytes()[j]{
            j += 1;
        }
        tmpvec.push(j);
        i +=1;
    }
   tmpvec
}

完整算法:https://qiaojinxia.github.io/chapter_7.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章