KMP算法的理解
1、符號(hào)約定
S:主串(長(zhǎng)度n)
i:主串S中當(dāng)前位置的下標(biāo)(從1開(kāi)始,S(0)放串長(zhǎng))
T:子串(長(zhǎng)度m)
j:子串T中當(dāng)前位置的下標(biāo)(從1開(kāi)始,T(0)放串長(zhǎng))
?
2、樸素模式匹配的做法
每次匹配失敗 i 回溯至上一次開(kāi)始位置的后一個(gè), j 回溯至1重新開(kāi)始匹配。算法復(fù)雜度是O(n*m)
?
3、樸素模式匹配為何性能不佳?
例子1:子串中每個(gè)字符各不相同
匹配到閃電所示位置時(shí)匹配失敗,按照樸素模式匹配的做法應(yīng)該回溯到 i=2,j=1處重新開(kāi)始匹配。但是實(shí)際上T中的“abcde”與S中的“abcde”已經(jīng)匹配成功,而T中各個(gè)字符又各不相同,因此下次匹配從i=6,j=1開(kāi)始即可。
例子2:子串中有重復(fù)部分
匹配到閃電所示位置時(shí)匹配失敗,由于“abc”是字符各不相同的串,因此,按照例子1中的做法,下次匹配不需要再比較前三個(gè)字符,可回溯到 i=4,j=1處開(kāi)始重新匹配。又,子串中的紅色部分與子串中的黃色部分相同,而紅色部分曾與主串中的一部分匹配成功,故子串中的黃色并沒(méi)有必要再和主串中的紅色匹配,因此最終可回溯至 i=6,j=3處開(kāi)始重新匹配。
總結(jié):在整個(gè)字符串匹配過(guò)程中,i 值其實(shí)根本就不用回溯,每次匹配失敗,可從匹配失敗處將串分開(kāi),則前半段的情況總符合例子1或例子2中的情形(其實(shí)兩個(gè)例子實(shí)質(zhì)相同)。因此只用考慮每次匹配失敗后 j 值需要回溯到哪個(gè)位置。
?
4、next [ j ] 函數(shù)
于是大牛們搞出了next [ j ] 函數(shù)來(lái)告訴大家每次匹配失敗后,j 值回溯到哪個(gè)位置才合理,以此避免大量不必要的回溯。next [ j ] 函數(shù)是子串的結(jié)構(gòu)具有的性質(zhì),與主串無(wú)關(guān)。
next [ j ] 的值為字符串中位置 j 之前的字符串的前綴和后綴的最長(zhǎng)共有元素的長(zhǎng)度值+1。
?
?
?
?
解釋幾個(gè)概念,(1)部分匹配值:字符串的前綴和后綴的最長(zhǎng)共有元素的長(zhǎng)度;(2)前綴:除最后一個(gè)字符外一個(gè)字符串的全部頭部組合;(3)后綴:除第一個(gè)字符外,一個(gè)字符串的全部尾部組合。例如,“desk”的前綴是“d”,“de”,“des”;后綴是“esk”,“sk”,“k”。
5、KMP算法
每次匹配失敗后,i 不回溯,j 回溯到next [ j ] 函數(shù)所指示的位置即KMP算法。
6、我當(dāng)初的疑惑
乍一看,如果 j =1時(shí)匹配失敗,那么 j 的值還是應(yīng)該是1,為何初始化next [ 1 ]=0呢? 這種情況對(duì)應(yīng)了第一個(gè)字符就匹配失敗,那么此時(shí), 需要i 值+1,next [ j ]在i+1后能剛好回到1,即不變,故需要初始化next [ j ]為0.
?
總結(jié)
- 上一篇: 单链表基本操作(可执行程序),二级指针使
- 下一篇: java中的与运算符