KMP中幾種Next陣列的求法

2021-10-08 02:49:52 字數 3161 閱讀 1245

今天覆習到 kmp 演算法時候發現考研教材上的 next 陣列和我之前學的不一樣,所以特地拎出來比對一下,順便總結。

因為我之前掌握的 kmp 是李煜東的《演算法競賽高階指南》上介紹的,而考研教材似乎更多用的是嚴蔚敏的《資料結構(c語言版)》,所以就對這兩種實現方式做整理。

競賽版設 p[i , j] 為模式串 p 從 i 到 j 位置上元素構成的子串,t 為當前子串中真字首與真字尾的最長匹配長度。

假設字串從下標 1 開始存放,即 p[1 , n] 為模式串。

nex[i] 表示「p 中以 i 結尾的真字尾」與「p 的真字首」能夠匹配的最長長度,即:nex[i] = max,其中 t < i 並且 p[i-t+1, i] = p[1 , t] 。

亦即,在 p[ 1 , j ] 中長度為 t 的真字首,應與長度為 t 的真字尾完全匹配,故 t 必來自集合:next(p, j) =

nex 陣列的求法

初始化 nex[1] = t = 0,假設nex[1, i-1] 已求出,下面求nex[i]。

不斷嘗試拓展匹配長度 t,如果拓展失敗(下乙個字元不相等),令 t 變為nex[t],直至 t 為 0(應該從頭開始匹配)。

如果能夠拓展成功,匹配長度 t 就增加1。nex[i] 的值就是 t 。

**塊

void

getnex

(const

char

*s)}

需要注意的是,該**無需優化,在演算法競賽中該效率已足夠優秀,為o(m+n)。

舉例:p

abab

abaa

next00

1234

51可以使用任意字串,並呼叫上述**求對應的 next 陣列。

嚴版設 p[i , j) 為模式串 p 從 i 到 j-1 位置上元素構成的子串,t 為當前子串中真字首與真字尾的最長匹配長度。

假設字串從下標 1 開始存放,即 p[1 , n] 為模式串。

nex[i] 表示「p 中以 i 結尾的真字尾」與「p 的真字首」能夠匹配的最長長度再加 1,即:nex[i] = max +1,其中 t < i 並且 p[i-t, i) = p[1 , t] 。特別的,nex[1] = 0,因為 p[1,1) 是個空串。

亦即,在 p[ 1 , j ] 中長度為 t 的真字首,應與長度為 t 的真字尾完全匹配,故 t 必來自集合:next(p, j) =

nex 陣列的求法

初始化 nex[1] = t = 0,假設nex[1, i-1] 已求出,下面求nex[i]。

不斷嘗試拓展匹配長度 t,如果拓展失敗(下乙個字元不相等),令 t 變為nex[t],直至 t 為 0(應該從頭開始匹配)。

如果能夠拓展成功,匹配長度 t 就增加1。nex[i] 的值就是 t + 1。

**塊

void

getnex

(const

char

*s)}

舉例與練習

下面通過乙個例子表述如何手工寫嚴版 next 表:

例如模式串為:aaaabaa

那麼列表就有:

j = 1 為空串,此時定義nex[j] = 0;

a j = 2 有1個字元,此時真字首與真字尾最長匹配長度為0,故nex[j] = 0+1;

aa j = 3 有2個字元,此時真字首與真字尾最長匹配長度為1,故nex[j] = 1+1;

aaa j = 4 有3個字元,此時真字首與真字尾最長匹配長度為2,故nex[j] = 2+1;

aaaa j = 5 有4個字元,此時真字首與真字尾最長匹配長度為3,故nex[j] = 3+1;

aaaab j = 6 有5個字元,此時真字首與真字尾最長匹配長度為0,故nex[j] = 0+1;

aaaaba j = 7 有6個字元,此時真字首與真字尾最長匹配長度為1,故nex[j] = 1+1;

所以如果理解了真字首與真字尾,寫next表就很簡單。

next表的優化

所謂的優化就是為了避免移動後仍然失配的情況,因為每次 t[i] 和 p[j] 失配後,我們是令 j = nex[j],然後再繼續比較 t[i] 和 p[j] 。因此一旦 t[i] 和 p[j] 失配時我們是一定知道 t[i] 不等於 p[j] 的, 此時如果 p[nex[j] ] = p[j] ,那顯而易見還是會失配,於是我們就要重複 j = nex[j] 直至匹配成功或演算法結束,所以我們就可以在計算 next 表的時候順便判斷一下轉移前後 p 的字元變不變。

具體做法是:

void

getnex

(const

char

*s)}

求優化後的 next 表,也叫 nextval 表,操作只需要在求普通的 next 表上加一步,即在求出真字首與真字尾的最長匹配長度 t 後,判斷 p[t+1] 是否等於 p[i] ,如果相等就令 nextval[i] = nextval[t+1] ,否則就 nextval = t + 1。

例如:求aaaabaa 的 nextval(0 0 0 0 4 0 0 )

p:aaaabaa

j = 1 為空串,此時定義nex[j] = 0;

a j = 2 有1個字元,t = 0,且p[t+1] == p[j],故nex[j] = nex[1] = 0;

aa j = 3 有2個字元,t = 1,且p[t+1] == p[j],故nex[j] = nex[2] = 0;

aaa j = 4 有3個字元,t = 2,且p[t+1] == p[j],故nex[j] = nex[3] = 0;

aaaa j = 5 有4個字元,t = 3,且p[t+1] != p[j],故nex[j] = 3+1;

aaaab j = 6 有5個字元,t = 0,且p[t+1] == p[j],故nex[j] = nex[1] = 0;

aaaaba j = 7 有6個字元,t = 1,且p[t+1] != p[j],故nex[j] = nex[2] = 0;

KMP演算法中Next陣列的求法

例如 序列號 1 2 3 4 5 6 7 8 模式串 a b a a b c a c next值 0 1 1 2 2 3 1 2 next陣列的求解方法是 第一位的next值為0,第二位的next值為1,後面求解每一位的next值時,根據前一位進行比較。首先將前一位與其next值對應的內容進行比較,...

next陣列求法和KMP演算法

首先介紹什麼是next陣列 定義 next i 表示是子串s 0 i 的最長相等前字尾的字首的最後一位下標。認真理解不難 下圖給出了next陣列的定義計算 其中下框第一行是字首,下框第二行是字尾 注意字首和字尾可以部分重疊但是不能使是s 0 i 本身 很好理解這是必然因為字首和字尾都是本身,比較毫無...

KMP演算法next求法

定義 1 next 0 1 意義 任何串的第乙個字元的模式值規定為 1。2 next j 1 意義 模式串t中下標為j的字元,如果與首字元 相同,且j的前面的1 k個字元與開頭的1 k 個字元不等 或者相等但t k t j 1 k 如 t abcabcad 則next 6 1,因t 3 t 6 3 ...