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
}