摘要:通過觀察發(fā)現(xiàn),如果匹配字符串中有相同的子字符串,那么的變化會有所不同。所以這個值的變化跟目標字符串沒什么關(guān)系,只跟自己的子字符串的重復(fù)性有關(guān)。的兩側(cè)子字符串相等,所以這時候倒數(shù)兩位位位代碼量不多但理解起來有點困難反正我理解了很久。
最近公司啟動小程序項目中,在搜索模塊有這么個功能需求:當(dāng)用戶輸入搜索內(nèi)容時實時地請求服務(wù)器得到一組較高匹配度的搜索關(guān)鍵字,在這些關(guān)鍵字中高亮顯示用戶的匹配輸入。
例如輸入“中國”
搜索關(guān)鍵字為“中國共產(chǎn)黨”
那我就想到了KPM算法,就打開《大話數(shù)據(jù)結(jié)構(gòu)》這本書來看看KPM到底是什么東西,倒騰了很久,終于對KPM算法有一點點點點點點了解,就來記錄一下。
傳統(tǒng)的字符串匹配算法傳統(tǒng)的字符串匹配算法是這樣子的:當(dāng)目標字符串和匹配字符串在匹配過程中發(fā)生失配,目標字符串下標和匹配字符串下標都要回溯,這會導(dǎo)致一些不必要的匹配判斷,舉個栗子。
當(dāng)匹配到第4位的時候,偶哦匹配失敗,那么將會從下面的位置開始匹配
但是我們明眼看去,很明顯是多余匹配判斷了嗎。
對沒錯,傳統(tǒng)的匹配算法會只是很簡單的匹配回溯匹配回溯,時間復(fù)雜度為O((n-m)*m),導(dǎo)致很多的匹配判斷是多余的,那么接下來的KPM算法就是解決這個笨重的問題的。
KMP算法是一種改進的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同時發(fā)現(xiàn),因此人們稱它為克努特——莫里斯——普拉特操作(簡稱KMP算法)。KMP算法的關(guān)鍵是利用匹配失敗后的信息,盡量減少模式串與主串的匹配次數(shù)以達到快速匹配的目的。具體實現(xiàn)就是實現(xiàn)一個next()函數(shù),函數(shù)本身包含了模式串的局部匹配信息。時間復(fù)雜度O(m+n)。
注:一下i代表目標字符串的下標,j代表匹配字符串的下標。
剛才講到,我們的KPM算法就是為了讓這沒必要的回溯發(fā)生,那么i不可變小,就只考慮變化j值了。通過觀察發(fā)現(xiàn),如果匹配字符串中有相同的子字符串,那么j的變化會有所不同。所以這個j值的變化跟目標字符串沒什么關(guān)系,只跟自己的子字符串的重復(fù)性有關(guān)。
next[j] = -1 // 當(dāng)j == 0時 = max{k|0例如:
j: 0 1 2 3 4 P: A B A B C next[j]:-1 0 0 1 2說白了就是j前的子字符串的重復(fù)字符有多少個,那么next[j]就是重復(fù)字符串個數(shù)。
next數(shù)組的作用就是KPM算法j值的回溯方案。
還是上面那么例子。當(dāng)i = 4, j = 4時C !== X ,那么這個時候j = next[j] = 2,所以只需進行target[i(為4)]和pattern[j(為2)]的判斷,而pattern[0]和pattern[1]分別的判斷省略掉了。說了那么多太干了,貼個代碼先。
var target = "ababxababc" var pattern = "ababc" function getKPMNext(str) { var i, j; var next = []; next[0] = -1; i = 0; j = -1; while(i < str.length - 1) { if (j == -1 || str[i] == str[j]) { next[++i] = ++j; } else { j = next[j]; } } return next; } // j = next[j] next[j]的兩側(cè)子字符串相等,所以這時候str[i] == str[j] 倒數(shù)兩位== 4 5位 == 1 2位 console.log(getKPMNext("abxabaabxabxa"))代碼量不多但理解起來有點困難(反正我理解了很久T_T)。j = -1的時候就是上述next數(shù)組在其他情況。
當(dāng)str[i] == str[j]的時候,那么i和j就很愉快地手牽手地前進。
當(dāng)str[i] != str[j]的時候,那么j就要回溯。然后就是KPM算法的主體了
function KPMMatch(target, pattern) { var i = 0, j = 0; var next = getKPMNext(pattern); while (i < target.length && j < pattern.length) { if (j == -1 || target[i] == pattern[j]) { ++i; ++j; } else { j = next[j]; } } if (j >= pattern.length) { return i - j; } return -1; }當(dāng)失配時j回溯,相對于傳統(tǒng)匹配省掉了不必要的匹配。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/85190.html
摘要:作者鐘離,酷家樂客戶端負責(zé)人原文地址酷家樂客戶端下載地址文章背景在酷家樂客戶端在改版成功后,我們積累了許多的寶貴的經(jīng)驗和最佳實踐。 作者:鐘離,酷家樂PC客戶端負責(zé)人原文地址:https://webfe.kujiale.com/electron-ku-jia-le-ke-hu-duan-kai-fa-shi-jian-fen-xiang-jin-cheng-tong-xin/酷家樂客...
摘要:作者鐘離,酷家樂客戶端負責(zé)人原文地址酷家樂客戶端下載地址文章背景在酷家樂客戶端在改版成功后,我們積累了許多的寶貴的經(jīng)驗和最佳實踐。 作者:鐘離,酷家樂PC客戶端負責(zé)人原文地址:https://webfe.kujiale.com/electron-ku-jia-le-ke-hu-duan-kai-fa-shi-jian-fen-xiang-jin-cheng-tong-xin/酷家樂客...
閱讀 4013·2021-10-12 10:12
閱讀 2954·2021-09-10 11:18
閱讀 3742·2019-08-30 15:54
閱讀 2884·2019-08-30 15:53
閱讀 714·2019-08-30 13:54
閱讀 1045·2019-08-30 13:21
閱讀 2317·2019-08-30 12:57
閱讀 1794·2019-08-30 11:10