KMP演算法 字串匹配問題

2021-10-08 06:34:58 字數 4112 閱讀 8135

package com.self.datastructure.algorithm.kmp;

/** * 暴力匹配演算法

* 演算法解析:

* * 對乙個字串a, 匹配目標子串a

* * 定義兩個變數, 字串a的起始標記i, 從0開始, 字串a的起始比較offset, 從0開始

* * 用a[i]匹配a[offset], 如果匹配則++

* * 如果不匹配, i移位到原始i的後一位, 因為過程中, i可能存在++操作

* * 但是i具體移位了多少是通過offset體現出來的, 所以i的後一位就是(i-j+1)

* @author pj_zhang

* @create 2020-07-05 12:33

**/public

class

violencematch

private

static

intviolencematch

(string source, string target)

// if條件符合, 說明已經查詢到第乙個位置, 進行後續位置查詢

if(i <= max)

else}}

// 沒有匹配到直接返回-1

return-1;}}

部分匹配表是部分匹配值的陣列,部分匹配值是字首和字尾的最長共有元素的長度,下以abcdabd舉例

至於部分匹配表的真正價值何在,下一步繼續分析

在字串string str = "bbc abcdab abcdabcdabd"中匹配模式串string childstr = "abcdabd"

首先進行第乙個字元比對,str.charat(0) = b比對childstr.charat(0) = a,匹配不成功,str索引後移,繼續比對,直到str.charat(4) = a比對childstr.charat(0) = a成功,開始後續字元匹配

後續字元順序匹配,在abcdab段是匹配正常,可以繼續匹配到,直到str.charat(10) = 空格比對childstr.charat(6) = d失敗

此時,按照暴力匹配演算法的原則,會回溯到初始匹配位置的下一位,即str.charat(5) = b,與模式串的第乙個字串,即childstr.charat(0) = a進行比對,如圖;此處問題在於之前的abcdab是已經匹配過的,已知的字串,並且abcdab的字尾兩位與字首兩位是一致的,也就是部分匹配值為2,是不需要再次進行匹配,可直接用ab的下一位匹配模式串的第三的;如果進行字尾兩位的識別及初始匹配索引的推進,就是kmp演算法接下來要處理的問題

在部分匹配表部分,我們已經算出字串abcdabd的部分匹配表為int arr = [0, 0, 0, 0, 1, 2, 0],其中索引對應的是字串中各個字元的索引位置,值代表以該字元及之前的字元組成乙個完整串時,對應的部分匹配值,如在索引5處,對應的字串是abcdab,其前字尾最長匹配串為ab,長度為2

繼續回到第三步,已知d不匹配,則前面abcdab六個字元是匹配的,從部分匹配表的對應索引5處尋找該字元的部分匹配值2位,說明前兩個字元是與模式串的前兩個字元相匹配的,即ab,那此時初始匹配位置需要移動到這個a的位置,即str[8];又因為ab已經匹配過,則直接從第三位開始匹配,即str.charat(10) = 空格比對childstr.charat(2) = c

移動位數 = 當前已匹配位數 - 部分匹配值 = 6 - 2 = 4位

因為空格與c不匹配,繼續部分匹配表中找c所在索引2對應的部分匹配值arr[2] = 0,則移動位數 = 2 - 0 = 2,繼續後續兩位

後移兩位後,空格與a不匹配,直接後移一位,注意此處不存在匹配,不考慮部分匹配規則;後移一位後a與a匹配,並繼續後續匹配到str.charat(17) = c比對childstr.charat(6) = d失敗

比對失敗後,因為已匹配字元是6個,對應的部分匹配值是arr[5] = 2,則後移4位,繼續從第三位開始進行匹配,直至匹配結束,全部7位匹配完成後,算匹配成功,返回當前匹配階段的主串初始索引index = 主串當前索引 - 匹配個數 + 1 = 21 - 7 + 1 = 15,至此全部匹配完成

package com.self.datastructure.algorithm.kmp;

/** * kmp演算法

* * 生成部分匹配表, 此處注意生成規則

* * 按照匹配字元依次向後匹配, 如果匹配後則繼續匹配,

* * 如果沒有匹配到, 按照已經匹配到的字元長度從部分匹配表中找到對應的部分匹配值, 即已匹配部分的字首

* * 匹配的首字元後移位數 = 當前已經匹配位數 - 部分匹配表中以匹配部分對應的值

* * 後移完成後, 繼續從上次匹配的斷點與子串需要新對應位置匹配, 匹配到繼續, 未匹配到重複步驟

* * 匹配完成後, 如果要進行所有子串匹配, 則後移子串位數, 繼續匹配即可

* @author pj_zhang

* @create 2020-07-07 17:35

**/public

class

kmp/**

* 通過kmp演算法進行匹配

* @param str 字串

* @param childstr 子串

* @return 返回索引

*/private

static

intkmp

(string str, string childstr)

// 如果匹配, 則j++ 繼續向後比較

if(str.

charat

(i)== childstr.

charat

(j))

// 如果j的值等於childstr的長度, 則匹配完成

if(j == childstr.

length()

)}return-1

;}/** * 部分匹配值陣列生成

* @param modelstr 字串

* @return 部分匹配值陣列

*/private

static

int[

]partmachin**alue

(string modelstr)

// 如果兩個字元相等, 說明已經匹配到了

if(modelstr.

charat

(i)== modelstr.

charat

(j))

arr[i]

= j;

}return arr;

}}

字串匹配問題 KMP匹配演算法

基本思想 字串匹配問題 在文字串中尋找是否有與模式串相同的子串 在字串匹配時,暴力匹配忽略了如果模式串開頭與中間有重複部分,在將模式串的後面的重複部分匹配後,無法繼續匹配的話,此時將模式串開頭實際上也已經被匹配了,可以直接從開頭重複部分之後開始匹配 這裡引入了乙個部分匹配值表,每個與模式串的字元對應...

字串匹配問題 KMP演算法

kmp演算法 kmp是解字串匹配這類題目的演算法,又稱 看毛片 演算法。如下圖,給定乙個長度為n的文字,給定乙個長度為m 的字串,求該字串在給定文字的中出現的次數。kmp就是解決這一類題目的。i 1 zzkzzzkzzzkzkkkz zzkzzkzzkzzk j 1繼續考慮上面的問題。首先我相信每個...

字串匹配問題 KMP演算法

字串匹配問題 給定兩個字串s 主串 和t 模式串 假設n strlen s strlen t m,判斷主串s中是否包含模式t,且返回t在s中所在的起始位置。這裡為簡單起見,若s包含t,則只返回第乙個t所在的位置。一般的蠻力法如下 蠻力法在遇到不匹配時,j每次都要回到t的起點,從新開始匹配,這樣來看效...