KPM匹配演算法

2021-10-20 13:11:44 字數 3277 閱讀 8827

在第一次匹配中,i從0開始,j從0開始。當i=2,j=2時匹配失敗,此時i回溯到1,j回溯到0。

第二次匹配中,i從1開始,j從0開始。當i=1,j=0時匹配失敗,此時i回溯到2,j回溯到0。

第三次匹配中,i從2開始,j從0開始。當i=6,j=4時匹配失敗,此時i回溯到3,j回溯到0。

第四次匹配中,i從3開始,j從0開始。當i=3,j=0時匹配失敗,此時i回溯到4,j回溯到0。

第五次匹配中,i從4開始,j從0開始。當i=4,j=0時匹配失敗,此時i回溯到5,j回溯到0。

第六次匹配中,i從5開始,j從0開始。i=10,j=5,t中全部字元比較完,匹配成功,返回本次匹配起始位置下標i - j。(i=9和j=4的時候匹配成功,i和j會再加一次,所以i=10,j=5)

ababaaab:字首:abbaaaab 字尾:ababaaab,重複的最大子串是abababa:字首:ababa 字尾:ababa,重複的最大子串是abaaaaa:字首:aaaa 字尾:aaaa,重複的最大子串aaa,此處需要注意的:前字尾的最大子串不可與父串相同,否則沒有意義。

什麼是字首的子串的最大位置+1

我們求出的前字尾的最大重複的公共子串,要分為字首和字尾兩部分,上部分的例子已經說明,而我們需要的是字首的部分,例如:

ababaaab:字首:abbaaaab,這樣我們取的位置就是 3,也就是長度+1,為什麼我們需要這部分呢?這與kpm演算法的執行過程有關,下面再重點說明。

怎麼求next陣列呢?

先展示一下code:

//先求出next陣列,具體思路

/* *陣列下標是出現不同的字元的位置【next陣列中需要每乙個都考慮到,即是遍歷所有】,值為回溯到的位置,相當於將字首的公共重複子串副高字尾的重複公共子串,這裡需要注意的是,字首與字尾的重複子串均不同與需要計算的

* 子串長度相同,否則沒有意義

* 是否相等,要是相等,則直接加入當前位置的最大重複子串【因為前面的最大子串是驗證過的,只需要確定當前的相同即可以確定】,若是不同,則回溯

* 回溯:這裡的回溯比較難理解,可以這樣理解,對於新增加的字串字元,我先不考慮與上一次最大重複子串的下乙個字元是否相同,而是直接右移,那麼此時,我記錄位置的指標對應的就是上一次最大子串的的下乙個元素

* 即回溯到該位置後,我進行比較,發現這兩個元素並不相同,那我應該怎麼辦呢?答案肯定是繼續右移,即當前這個位置對應的最大重複的字串的位置【next陣列中對應的回溯位置】

* 那麼再求該位置的最大重複子串時候就會轉化為移動後的位置的最大子串 即最大子串指標的位置 = next[當前最大子串指標的位置],若是與新增加的字元相等了+1後則是該位置對應的指標位置,否則則繼續右移,直至相同,就是該

* 位置需要回溯的位置。

*/private

int[

] next;

public

void

findnext

(string str)

else

}}

下面我們通過乙個例子來手動計算乙個next陣列,並與上面的**對應一下

我們假設乙個字串為ababa

第一步,由於在字串匹配的時候任意位置都有可能與源串匹配出不同,那麼我們就要考慮到所有的情況,即遍歷t,並求出每一位置的前部分子串的前字尾的最大公共重複的子串

假設遍歷t的指標為j,字首的指標為k,對於求最大公共重複的子串我們分為三種情況:①j=1時,next[1]= 0,②當含有重複公共子串的時候,next[j+1]=k+1【這也是上面為什麼求字首的最大重複子串+1的座標,即k+1】,③當沒有重複公共子串的時候,next[j+1] = 1。記住上面三種情況,那麼我們開始進行遍歷【記住,我們從1開始遍歷的,並不是0,也就是第乙個a的座標為1

j=1時,此時next[1] = 0

當j=2時,我們得到 a ,我們不考慮現在指標正在指向的字元【b】,它之前的只有乙個a,沒有最大重複子串,即next[2] = 1

當j=3時,我們得到ab,也沒有,則next[3] = 1

當j=4時,我們得到aba,此時的字首最大串是a,即a的位置+1 = 2,則next[4] = 2

當j=5時,我們得到abab,此時的字首最大串是ab,即b的位置+1 = 3,則next[5] = 3

當j=6時,我們得到ababa,此時的字首最大串是aba,則a的位置+1 = 4,則next[6] = 4,這樣就完成了遍歷,得到了陣列next。

那這個next陣列是怎麼使用的呢?

我們先看**

/**

** @param str 需要匹配的子串

* @param targetstr 被匹配的子串

* @param position 開始的位置

* @return 是否匹配成功

*/public

boolean

kpmmethod

(string str,string targetstr,

int position)

else

}return positionpoint != str.

length()

;}

下面我們看一下執行過程

kpm字串匹配演算法

首先是簡單的樸素匹配演算法 返回子串t在主串s的位置,若不存在則返回0 public static intindex string s,string t else if j t.length return 0 舉例說明 s是 abcabcabd t是 abcabd,樸素的匹配演算法每次發現不對都要重...

字串匹配的KPM演算法

轉至 字串匹配是計算機的基本任務之一。舉例來說,有乙個字串 bbc abcdab abcdabcdabde 我想知道,裡面是否包含另乙個字串 abcdabd 許多演算法可以完成這個任務,knuth morris pratt演算法 簡稱kmp 是最常用的之一。它以三個發明者命名,起頭的那個k就是著名科...

kpm演算法理解

kpm演算法,是資料結構課本中串的模式匹配部分講解的演算法。它的需求是求解給定字串是否包含指定的字串。給定乙個主串s及乙個模式串p,判斷模式串是否為主串的子串 若是,返回匹配的第乙個元素的位置 序號從1開始 否則返回0 如s abcd p bcd 則返回2 s abcd p acb 返回0。kpm優...