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的起點,從新開始匹配,這樣來看效...