kmp算法實現思路及其代碼演示

一、什麼是kmp算法?

去百度上搜素一下,你會得到下面一段話:

KMP算法是一種改進的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人們稱它爲克努特—莫里斯—普拉特操作(簡稱KMP算法)。KMP算法的核心是利用匹配失敗後的信息,儘量減少模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是通過一個next()函數實現,函數本身包含了模式串的局部匹配信息。

乍一看,是不是有點懵逼?什麼next函數、什麼局部匹配,我沒看懂啊! 沒關係,看了我的這篇博文,一定幫你把kmp算法安排的明明白白。

二、實例介紹

很多人想學kmp算法,可能是因爲遇到字符串匹配問題:

有一個字符串str1 = “bbc abcdab abcdabcdabde” 和 一個字串 str2 = “abcdabd”
現在判斷str1是否包含str2,如果存在,就返回第一次出現的位置,如果沒有,就返回-1.

遇到這種問題,如果之前沒學過kmp算法,肯定第一反應:暴力匹配法。就是一個個字符進行對比,直到每一個字符相同爲之。但是,你也應該能意識到,這樣會特別的耗時,而且程序會非常的不簡潔。

那我們就先通過實現暴力匹配法,引出我們的kmp算法。

三、暴力匹配法的實現思路及其代碼演示

實現思路:

  1. 假設我們給定現在str1 匹配到 i 位置,str2 匹配到 j 位置。如果當前字符匹配成功(str[i] = str[j]) ,則i++、j++,繼續匹配下一個字符。
  2. 如果匹配失敗。(str[i] != str[j]) 令 i = i -(j-1),j = 0; 就相當於匹配失敗以後,i回溯,j重新被賦值爲0.
    注:暴力匹配法可能思路上唯一難點就是這個了。
  3. 整體的思路就是這樣,可以看出。每當我們匹配不成功以後,就會重新回溯一遍,相當的耗時耗力。

代碼演示:

在這裏插入圖片描述
每一步都有詳細的註釋,應該挺容易理解的。
介紹完暴力匹配法,下面我們就來講講kmp算法。

四、kmp算法的實現思路

依然用上面那個例子

1.首先str1的第一位與str2的第一位進行比較,如果不合適,則往後移一位:
在這裏插入圖片描述
2.重複第一步,不合適,繼續往後移:
在這裏插入圖片描述
3.直到str1的第一個字符與str2的第一個字符相匹配:
在這裏插入圖片描述
4.接着比較,還是符合:
在這裏插入圖片描述
5.直至匹配到兩個位置字符不相符爲止:
在這裏插入圖片描述

6.如果按照我們之前暴力匹配法的方式,肯定是將str1後移一位,然後與str2重新進行比較。這樣是非常不明智的,因爲BCD之前已經比較過了。當空格與D不匹配時,你已經知道前面六個字符是ABCDABD。kmp算法的思路是,設法通過這種已知的信息,不要把“搜索位置”移回到已經比較過的位置,繼續把他往後移,這樣就提高了效率。

我的理解是這樣的,比如:你的一個子字符串是“A”開頭,那麼當你第一次匹配不成功時,往後移,移到下一個”A“開始,進行下一次匹配。那麼你怎麼知道到底移動幾位,到達下一個A的位置呢?這是就要引入一個公式

移動位數 = 以匹配字符數 - 對應的部分匹配值

什麼是部分匹配值

在這裏插入圖片描述
這就涉及到前綴與後綴的問題。

什麼叫前綴與後綴?

比如說:有一個字符串 ABCDE
那麼他的前綴就是去掉E 得到 A、AB、ABC、ABCD

後綴就是去掉A 得到 BCDE、CDE、DE、E

當前後綴有一個相等時,共有元素的長度如果爲 1 那麼部分匹配值就是 1 …

所以我們很容易的知曉:

A 沒有前綴與後綴 所以他的部分匹配值是 0
AB 他的前綴是 A 後綴是 B 所以部分匹配值是 0
ABC 他的前綴是 A AB 後綴是 BC C 所以部分匹配值也是 0
ABCD 他的前綴是 A AB ABC 後綴是 BCD CD D 所以部分匹配值也是 0
ABCDA 他的前綴是 A AB ABC ABCD 後綴是 BCDA CDA DA A 有一個相同,其長度爲1,所以部分匹配值是 1
ABCDAB 他的前綴是 A AB ABC ABCD ABCDA 後綴是 BCDAB CDAB DAB AB B 有1個相同,其長度爲2,所一部分匹配值是 2
ABCDABD 他的前綴是 A AB ABC ABCD ABCDA ABCDAB 後綴是 BCDABD CDABD DABD ABD BD D 所以部分匹配值爲 0

得到一個字串的部分匹配值以後

我們將以匹配的位數(如題目所示,六位相同,所以爲6)減去 對應的部分匹配值(即最後一位匹配數,題目上是D 對應的是 2 )

這樣後移4位 進行下一次比較~

口說無憑,上代碼~

五、kmp算法的代碼演示

在這裏插入圖片描述
代碼還是比較簡單的,主要的難點,在我看來就是kmp算法核心 那一塊的代碼,我也進行了註釋

從代碼中,我們不難看出,用kmp算法解決這些問題,大大減少了代碼的時間複雜度,使代碼運行的效率更高。真的很不錯~

大家多多理解,一起加油呀~

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