新人向 KMP字串匹配演算法

2021-10-06 17:41:06 字數 3017 閱讀 5275

**reference

很久沒有更新了(因為這段時間確實很混)

這次演算法小白給大家介紹乙個kmp字串匹配演算法。

一看到字串匹配,我就想起了以前做過的一種暴力破解的方法(也是唯一我能自己想到的做法)。

對了,為了方便起見,這篇部落格中,我們把需要找的字串我們稱之為pattern,從什麼地方找的目標字串稱為target

它的思想很簡單,例如:target為abababccb,pattern為ababc,那麼我們要做的事就是逐個比較

target01

2345

678-

abab

abcc

b pattern01

234-

abab

c首先target的第0格的a跟pattern的第0格的a匹配,然後b跟b,b跟c不匹配,那麼從target第1格開始重新比較…

寫三個迴圈控制變數,兩個用來記錄target和pattern中匹配字串的開頭位置,最後乙個用來記錄target中正在匹配的位置即可。

請大家仔細觀察:

在第一趟中,target和pattern的第4格字元不同,於是我們又重新開始第二趟,哇,有沒有辦法能夠不那麼費勁呢?

當然有了,n年前,三個大佬發明了乙個演算法,就叫做kmp演算法,來解決這個問題。

首先我們需要了解乙個概念:最長公共前字尾

公共前字尾就是:例如說abab,它前數兩格ab和後數兩格ab是一樣的,他們就是公共前字尾。

再舉個例子,abcaba,它的最長公共前字尾就是1,abbc,它的最長公共前字尾就是0,這下應該知道它是什麼了吧。

請大家看一下pattern的最長公共前字尾是多少。

答案是2。

另外,公共前字尾不能為字串本身(如果是的話豈不是所有最長公共前字尾大小都為本身了?)

那麼它又有什麼用呢?

還是拿上邊例子舉例,它的作用在於

當第一趟的第四格不匹配時,我能夠不用重新比較target的34格和pattern的12格,(因為target的12格pattern的12,且因為pattern的最長公共前字尾是2,pattern的12格pattern的34格,所以不必重新比較,可以直接從target的4格跟pattern的3格來看是否匹配。

總而言之,它的作用在於我們能夠不必重新匹配前面屬於前字尾的已經匹配過的子串(如果沒有前字尾,那麼還是要重新匹配的)

一、打出字首表(方便查詢使用)

關於這個表我還是再拿上面的pattern舉個例子 (pattern:又拿我?)。

pattern01

234-

abab

cprefix_table00

120prefix_table我們人寫起來簡單,但是**怎麼寫呢?

仔細觀察0~2的aba,它的最長公共前字尾是1,那麼:若想要0~3的字串最長公共前字尾為2,是不是只要第三格是第一格就可以了。

如此它們存在一定的關係。

但是如果不匹配,情況就不一樣了。

不能簡單的令prefix_table中對應格數為0。

舉例子:

如aba和abac,這裡第三格的c跟第一格b不匹配,確實它的最長公共前字尾為0。

但是如果是aba和abaa呢,第三格的a和第一格的b不匹配,但是答案是1。

因為你沒法保證後半部分的子串會不會和字首開始的子串有公共部分

也就是說又要重新匹配了嗎?

是的,但是我們可以再利用kmp的思維進行匹配。(禁止套娃)

前邊說過,不匹配的時候只要把pattern當前位的前面的子串的最長公共前字尾位置開始比較就可以,那麼這裡也是一樣。

最後實現時為了方便,把prefix_table全部向右移動一格(最後一位丟掉),第一位補-1(也可以是別的),這裡我們會在傳參的時候巧妙處理(見下)

二、正式進行kmp匹配

這部分就像上面引言講的那樣了,其實打表相對複雜,這部分可以去看動畫,然後根據**理解。

kmp模式搜尋演算法動畫演示

注釋已經比較清楚了,要注意的是邊界情況,避免一些段錯誤的發生。

#include

#include

//初始化字首表

//pattern: 模式字串(要比較的)

//prefix_table: 字首表

//n: 字串的長度

void

prefix_table_init

(char pattern,

int prefix_table,

int n)

else

else}}

}//target: 目標字串(你要從那裡找的)

void

kmp_search

(char pattern,

char target,

int prefix_table)

if(target[i]

== pattern[j]

)else

//否則從....開始匹配

else}}

if(count ==1)

}int

main

(int argc,

char

*ar**)

;//prefix_table[0]初始化為-1

prefix_table_init

(pattern, prefix_table +

1, len -1)

;//最後一位其實用不著

kmp_search

(pattern, target, prefix_table)

;return0;

}

kmp字串匹配演算法1

kmp字串匹配演算法2

【soso字幕】汪都能聽懂的kmp字串匹配演算法【雙語字幕】

(看了第三個才懂了,等等這標題怎麼怪怪的)

KMP演算法 字串匹配

kmp演算法基本思想 我們在用常規的思想做 字串匹配時候是 如 對如 字元如果 t abab 用p ba 去匹配,常規思路是 看 t 第乙個元素 a 是否 和p 的乙個 b 匹配 匹配的話 檢視各自的第二個元素,不匹配 則將 t 串的 第二個元素開始 和 p 的第乙個匹配,如此 一步一步 的後移 來...

KMP字串匹配演算法

kmp核心思想 計算模式串的next陣列,主串的索引在比較的過程中不回朔 ifndef kmp h define kmp h class kmp endif include kmp.h include include include using namespace std int kmp calcu...

KMP字串匹配演算法

在介紹kmp演算法之前,先介紹一下bf演算法。一.bf演算法 bf演算法是普通的模式匹配演算法,bf演算法的思想就是將目標串s的第乙個字元與模式串p的第乙個字元進行匹配,若相等,則繼續比較s的第二個字元和p的第二個字元 若不相等,則比較s的第二個字元和p的第乙個字元,依次比較下去,直到得出最後的匹配...