自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

徹底理解字符串匹配KMP算法

開(kāi)發(fā) 前端
如果下一個(gè)字符相同,那么當(dāng)前位置next數(shù)組的值就是n+1。而如果下一個(gè)字符不相同,我們繼續(xù)查找next[n-1],然后前一個(gè)指針回退,繼續(xù)比較下一個(gè)位置即可。

大家好,我是小風(fēng)哥,今天簡(jiǎn)單聊聊字符串匹配kmp算法。

字符串匹配是計(jì)算機(jī)科學(xué)中非?;A(chǔ)的操作,給定兩個(gè)字符串a(chǎn)和b,我們需要判斷字符串a(chǎn)是否包含字符串b。

圖片圖片

像你我這樣的普通程序員能想到的最簡(jiǎn)單方法是這樣的,用字符串b不斷去匹配每個(gè)主串中的子串。

假設(shè)給定這樣兩個(gè)字符串:

圖片圖片

首先從主串的第一個(gè)位置和子串的第一個(gè)位置去匹配,我們發(fā)現(xiàn)A和B不相同:

圖片圖片

因此主串指針后移一位,子串重新從最第一個(gè)字符開(kāi)始匹配。

圖片圖片

這時(shí)我們發(fā)現(xiàn)A和C不同,因此匹配失敗。

圖片圖片

主串指針回退到第三個(gè)字符,子串重新從第一個(gè)字符開(kāi)始匹配。

圖片圖片

此時(shí)B和A又不同,重復(fù)上述過(guò)程。

這次成功找到多個(gè)相同的字符,但最后一個(gè)字符匹配失?。?/p>

圖片圖片

按照我們的算法,主串指針需要回退到第5個(gè)字符重新匹配。

圖片圖片

這就是你我這種肉體凡胎能想到的算法,時(shí)間復(fù)雜度是O(mn),效率低下的原因當(dāng)然是主串指針需要回退。

然而有三位大神不是這么想的,它們跳出來(lái)凡人的思考方式發(fā)明了一種極具創(chuàng)意的算法,由于是三個(gè)人同時(shí)發(fā)現(xiàn),因此這個(gè)算法取了三人名字的首字母,這就是著名的kmp算法。

圖片圖片

看到這里相信你就能明白為什么這個(gè)算法很難掌握了吧,難是正常的,覺(jué)得不難才不正常,如果你能無(wú)師自通搞定kmp算法,那么早出生幾十年你也能和大師們并駕齊驅(qū)供我等凡夫俗子瞻仰。

廢話不多說(shuō),接下來(lái)就讓我們領(lǐng)略一下大師的非凡境界。

注意看這個(gè)主串指針,大師們思考的第一個(gè)問(wèn)題就是,主串指針是否有必要回退,這是最關(guān)鍵最核心的問(wèn)題。

圖片圖片

讓我們回到剛才部分匹配的示例。

主串指針是否需要需要回退呢?我們思考兩種可能。

第一種可能,即使能匹配成功,匹配成功的起始位置也在主串指針H及以后,在這種情況下主串指針不需要回退。

圖片圖片

第二種可能,匹配成功的起始位置經(jīng)過(guò)主串指針H:

圖片圖片

在這種情況下,主串指針之前的兩個(gè)字符A和B一定是成功匹配了的:此時(shí)我們只需要比較主串指針H及以后的位置即可。

圖片圖片

只有這么兩種可能。

因此可以看到,主串指針根本就沒(méi)有必要回退。

現(xiàn)在我們知道了主串指針不需要回退,那么子串指針該從哪里開(kāi)始匹配呢?從頭開(kāi)始嗎?

圖片圖片

注意看我們剛才提到的第二種可能,匹配成功的起始位置經(jīng)過(guò)主串指針H,在這種情況下,主串指針之前的兩個(gè)字符A和B一定是成功匹配了的,這意味著什么呢?

圖片圖片

這意味著AB是這個(gè)字符串的后綴:

圖片圖片

AB是這個(gè)字符串的前綴:

圖片圖片

不要忘了這兩個(gè)字符串是成功匹配了的:

圖片圖片

也就是說(shuō)這是兩個(gè)完全相同的字符串,這就意味著AB是成功匹配字符串的相同前后綴。

圖片圖片

這樣子符串指針也不需要回退到起始位置,而是從共同前后綴的下一個(gè)位置開(kāi)始匹配即可。

圖片圖片

而對(duì)于部分匹配的子串根本不存在共同前后綴的情況,

圖片圖片

我們直接從子串起始位置進(jìn)行匹配。

圖片圖片

可以看到,由于主串指針不回退,這大幅提高了算法的效率。

想要實(shí)現(xiàn)這樣的算法,關(guān)鍵是怎樣計(jì)算出部分匹配子串的共同前后綴。

因此我們來(lái)到了第二個(gè)核心問(wèn)題。

我們以ABCDAB為例來(lái)講解。

這是長(zhǎng)度為1的前后綴,這是長(zhǎng)度為2的前后綴,以此類(lèi)推。

圖片圖片

可以看到,在所有的前后綴中,相同前后綴的最大長(zhǎng)度是2。

圖片圖片

我們記下來(lái)。

實(shí)際上我們需要把所有子串的相同前后綴都計(jì)算出來(lái)。

對(duì)于ABCDA這個(gè)子串來(lái)說(shuō),相同前后綴長(zhǎng)度是1,因?yàn)閮蓚€(gè)A是相同前后綴。

圖片圖片

而對(duì)于ABCD這個(gè)子串來(lái)說(shuō),相同前后綴的長(zhǎng)度是0,也就是沒(méi)有相同的前后綴。

其它也一樣。

這樣我們就到了一個(gè)數(shù)組,通過(guò)查找這個(gè)數(shù)組我們能知道任意子串的共同前后綴長(zhǎng)度。

圖片圖片

這個(gè)數(shù)組在很多資料中被稱(chēng)之為next數(shù)組。

有了next數(shù)組就簡(jiǎn)單了。

假設(shè)此時(shí)我們發(fā)現(xiàn)兩個(gè)指針指向的字符不同,接下來(lái)只需要簡(jiǎn)單查找next數(shù)組:

圖片圖片

發(fā)現(xiàn)已匹配部分的相同前后綴長(zhǎng)度是2:

圖片圖片

因此主指針不動(dòng),子串指針移動(dòng)到相同前后綴的下一個(gè)位置繼續(xù)去匹配即可。

圖片圖片

可以看到,只要我們能得到next數(shù)組,就可以在線性時(shí)間復(fù)雜度內(nèi)解決問(wèn)題。

這里,我們來(lái)到了第三個(gè)核心問(wèn)題,那就是該怎樣高效計(jì)算出next數(shù)組。

假設(shè)此時(shí)我們已經(jīng)計(jì)算出了這個(gè)子串的共同前后綴,也就是長(zhǎng)度為n的這兩個(gè)部分。

圖片圖片

接下來(lái)計(jì)算下一個(gè)位置的最長(zhǎng)前后綴,我們只需要分別后移兩個(gè)指針,然后比較字符是否相等,這里有兩種可能。

第一種可能是接下來(lái)的字符相同,那么這個(gè)子串的最長(zhǎng)相同前后綴的長(zhǎng)度就是n+1。

圖片圖片

然后寫(xiě)到next數(shù)組即可,這很好理解。

圖片圖片

但是如果下一個(gè)位置的字符不相等該怎么辦呢?

注意接下來(lái)是整個(gè)算法最核心的,也是最具技巧的地方。

如果接下來(lái)的兩個(gè)字符不相等,那么前面的這部分絕無(wú)可能形成最長(zhǎng)前后綴。

圖片圖片

因此我們只能找一個(gè)更短的。

圖片圖片

如果能找到一個(gè)更短的,這就意味著這兩部分會(huì)形成一個(gè)共同前后綴。

圖片圖片

然后我們繼續(xù)比較下一個(gè)字符就可以了,這就回到最初的問(wèn)題。

那么這兩部分相同意味著什么呢?

不要忘了紅色部分是我們之前找到一個(gè)共同前后綴,也就是說(shuō)紅色部分的子串完全相同。

圖片圖片

而現(xiàn)在這兩個(gè)子串也相同,這就意味著這兩個(gè)更小的子串其實(shí)是紅色部分子串的最長(zhǎng)前后綴。

圖片圖片

不要忘了,此時(shí)我們的指針已經(jīng)來(lái)到了這里,前面這部分的next數(shù)組已經(jīng)計(jì)算出來(lái)了。

圖片圖片

通過(guò)查next數(shù)組,我們可以快速得到更短前后綴的長(zhǎng)度。

既然紅色部分的長(zhǎng)度是n,那么更短前后綴的長(zhǎng)度其實(shí)就是next[n-1]。

圖片圖片

再來(lái)看下,紅色部分的長(zhǎng)度是n,那么更短前后綴的長(zhǎng)度是next[n-1]。

也就是這個(gè)位置。

圖片圖片

這就是計(jì)算next數(shù)組源代碼中n=next[n-1]這句話的含義。

圖片圖片

現(xiàn)在我們?cè)賮?lái)看一遍整個(gè)過(guò)程。

此時(shí)兩個(gè)字符的長(zhǎng)度不等,那么我們只需要簡(jiǎn)單查一下next[n-1]:

圖片圖片

這就是更短的前后綴長(zhǎng)度,假設(shè)是4。

圖片圖片

此時(shí)前一個(gè)指針回退到位置4,繼續(xù)比較下一個(gè)字符即可。

圖片圖片

如果下一個(gè)字符相同,那么當(dāng)前位置next數(shù)組的值就是n+1。

而如果下一個(gè)字符不相同,我們繼續(xù)查找next[n-1],然后前一個(gè)指針回退,繼續(xù)比較下一個(gè)位置即可。

圖片圖片

這就是完整的kmp算法實(shí)現(xiàn),可以看到整個(gè)代碼實(shí)際上只有30多行。

如果你能在50多年前寫(xiě)出這幾行代碼,你也能和它們并列,在計(jì)算機(jī)科學(xué)史上會(huì)留下你的一筆。

圖片圖片

好啦,以上就是本期全部?jī)?nèi)容。

責(zé)任編輯:武曉燕 來(lái)源: 碼農(nóng)的荒島求生
相關(guān)推薦

2013-05-06 10:54:08

字符串字符串匹配KMP算法

2014-10-30 14:19:13

本文由簡(jiǎn)單的字符串匹配

2011-06-22 10:45:19

JAVA

2010-03-18 08:59:29

JVM字符串JVM常量池

2023-04-11 08:54:57

字符串匹配算法

2023-12-15 10:27:01

暴力匹配算法Python字符串

2013-05-06 10:49:21

Boyer-Moore算法字符串匹配

2009-08-07 14:46:59

C#匹配字符串

2021-09-03 09:41:36

字符串時(shí)間復(fù)雜度

2009-11-18 12:38:04

PHP字符串函數(shù)

2016-12-30 13:32:24

字符串算法代碼

2023-02-26 22:33:32

字符串排列算法

2011-03-15 15:20:46

2024-03-04 15:05:37

2024-06-26 07:58:06

2018-11-30 10:00:53

Python字符串編程語(yǔ)言

2016-12-30 13:16:51

字符串算法代碼

2009-09-02 13:41:57

C#字符串操作

2009-08-11 10:26:49

C#算法C#字符串反轉(zhuǎn)

2021-09-10 08:31:54

翻轉(zhuǎn)字符串單詞
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)