演算法出處:matrix67大神,
除了字串匹配、查詢回文串、查詢重複子串等經典問題以外,日常生活中我們還會遇到其它一些怪異的字串問題。比如,有時我們需要知道給定的兩個字串「有多像」,換句話說兩個字串的相似度是多少。在自然語言處理中,這個概念非常重要,例如我們可以根據這個定義開發出一套半自動的校對系統:查詢出一篇文章裡所有不在字典裡的單詞,然後對於每個單詞,列出字典裡與它的levenshtein距離小於某個數n的單詞,讓使用者選擇正確的那乙個。n通常取到2或者3,或者更好地,取該單詞長度的1/4等等。這個想法倒不錯,但演算法的效率成了新的難題:查字典好辦,建乙個trie樹即可;但怎樣才能快速在字典裡找出最相近的單詞呢?2023年,**科學家vladimir
levenshtein給字串相似度做出了乙個明確的定義叫做levenshtein距離,我們通常叫它「編輯距離」。
字串a到b的編輯距離是指,只用插入、刪除和替換三種操作,最少需要多少步可以把a變成b。例如,從fame到gate需要兩步(兩次替換),從game到acm則需要三步(刪除g和e再新增c)。levenshtein給出了編輯距離的一般求法,就是大家都非常熟悉的經典動態規劃問題。
這個問題難就難在,levenshtein的定義可以是單詞任意位置上的操作,似乎不遍歷字典是不可能完成的。現在很多軟體都有拼寫檢查的功能,提出更正建議的速度是很快的。它們到底是怎麼做的呢?2023年,burkhard和keller提出的bk樹有效地解決了這個問題。這個資料結構強就強在,它初步解決了乙個看似不可能的問題,而其原理非常簡單。
首先,我們觀察levenshtein距離的性質。令d(x,y)表示字串x到y的levenshtein距離,那麼顯然:
最後這乙個性質叫做三角形不等式。就好像乙個三角形一樣,兩邊之和必然大於第三邊。
給某個集合內的元素定義乙個二元的「距離函式」,如果這個距離函式同時滿足上面說的三個性質,我們就稱它為「度量空間」。我們的三維空間就是乙個典型的度量空間,它的距離函式就是點對的直線距離。度量空間還有很多,比如manhattan距離,圖論中的最短路,當然還有這裡提到的levenshtein距離。就好像並查集對所有等價關係都適用一樣,bk樹可以用於任何乙個度量空間。
建樹的過程有些類似於trie
首先我們隨便找乙個單詞作為根(比如game)。以後插入乙個單詞時首先計算單詞與根的levenshtein距離:如果這個距離值是該節點處頭一次出現,建立乙個新的兒子節點;否則沿著對應的邊遞迴下去。例如,我們插入單詞fame,它與game的距離為1,於是新建乙個兒子,連一條標號為1的邊;下一次插入gain,算得它與game的距離為2,於是放在編號為2的邊下。再下次我們插入gate,它與game距離為1,於是沿著那條編號為1的邊下去,遞迴地插入到fame所在子樹;gate與fame的距離為2,於是把gate放在fame節點下,邊的編號為2。
查詢操作異常方便
如果我們需要返回與錯誤單詞距離不超過n的單詞,這個錯誤單詞與樹根所對應的單詞距離為d,那麼接下來我們只需要遞迴地考慮編號在d-n到d+n範圍內的邊所連線的子樹。由於n通常很小,因此每次與某個節點進行比較時都可以排除很多子樹。
舉個例子,假如我們輸入乙個gaie,程式發現它不在字典中。現在,我們想返回字典中所有與gaie距離為1的單詞。我們首先將gaie與樹根進行比較,得到的距離d=1。由於levenshtein距離滿足三角形不等式,因此現在所有離game距離超過2的單詞全部可以排除了。比如,以aim為根的子樹到game的距離都是3,而game和gaie之間的距離是1,那麼aim及其子樹到gaie的距離至少都是2。
於是,現在程式只需要沿著標號範圍在1-1到1+1裡的邊繼續走下去。我們繼續計算gaie和fame的距離,發現它為2,於是繼續沿標號在1和3之間的邊前進。遍歷結束後回到game的第二個節點,發現gaie和gain距離為1,輸出gain並繼續沿編號為1或2的邊遞迴下去(那條編號為4的邊連線的子樹又被排除掉了)……
實踐表明,一次查詢所遍歷的節點不會超過所有節點的5%到8%,兩次查詢則一般不會17-25%,效率遠遠超過暴力列舉。適當進行快取,減小levenshtein距離常數n可以使演算法效率更高。
從編輯距離 BK樹到文字糾錯
搜尋引擎裡有乙個很重要的話題,就是文字糾錯,主要有兩種做法,一是從詞典糾錯,一是分析使用者搜尋日誌,今天我們 使用基於詞典的方式糾錯,核心思想就是基於編輯距離,使用bk樹。下面我們來逐一 1965年,科學家vladimir levenshtein給字串相似度做出了乙個明確的定義叫做levenshte...
編輯距離及編輯距離演算法
編輯距離概念描述 編輯距離,又稱levenshtein距離,是指兩個字串之間,由乙個轉成另乙個所需的最少編輯操作次數。許可的編輯操作包括將乙個字元替換成另乙個字元,插入乙個字元,刪除乙個字元。例如將kitten一字轉成sitting sitten k s sittin e i sitting g 俄...
編輯距離及編輯距離演算法
include include include using namespace std const int max 1001 int maxlen max max int maxlen string str1,string str2 return maxlen len1 len2 int main ...