字符串相似度算法——Levenshtein Distance算法
Levenshtein Distance 算法,又叫?Edit Distance 算法,是指兩個字符串之間,由一個轉(zhuǎn)成另一個所需的最少編輯操作次數(shù)。許可的編輯操作包括將一個字符替換成另一個字符,插入一個字符,刪除一個字符。一般來說,編輯距離越小,兩個串的相似度越大。
?
算法實現(xiàn)原理圖解:
a.首先是有兩個字符串,這里寫一個簡單的 abc 和 abe
b.將字符串想象成下面的結(jié)構(gòu)。
A 處?是一個標(biāo)記,為了方便講解,不是這個表的內(nèi)容。
| ? | abc | a | b | c |
| abe | 0 | 1 | 2 | 3 |
| a | 1 | A處 | ? | ? |
| b | 2 | ? | ? | ? |
| e | 3 | ? | ? | ? |
c.來計算 A 處?出得值
它的值取決于:左邊的 1、上邊的 1、左上角的 0。
按照 Levenshtein distance 的意思:
上面的值加 1 ,得到 1+1=2 ,
左面的值加 1 ,得到 1+1=2 ,
左上角的值根據(jù)字符是否相同,相同加 0 ,不同加 1 。A 處由于是兩個 a 相同,左上角的值加 0 ,得到 0+0=0 。
然后從我們上面計算出來的 2,2,0 三個值中選取最小值,所以 A 處的值為 0 。
d.于是表成為下面的樣子
| ? | abc | a | b | c |
| abe | 0 | 1 | 2 | 3 |
| a | 1 | 0 | ? | ? |
| b | 2 | B處 | ? | ? |
| e | 3 | ? | ? | ? |
在 B 處?會同樣得到三個值,左邊計算后為 3 ,上邊計算后為 1 ,在 B 處?由于對應(yīng)的字符為 a、b ,不相等,所以左上角應(yīng)該在當(dāng)前值的基礎(chǔ)上加 1 ,這樣得到 1+1=2 ,在(3,1,2)中選出最小的為 B 處的值。
e.于是表就更新了
?
| ? | abc | a | b | c |
| abe | 0 | 1 | 2 | 3 |
| a | 1 | 0 | ? | ? |
| b | 2 | 1 | ? | ? |
| e | 3 | C處 | ? | ? |
C 處?計算后:上面的值為 2 ,左邊的值為 4 ,左上角的:a 和 e 不相同,所以加 1 ,即 2+1 ,左上角的為 3 。
在(2,4,3)中取最小的為 C 處的值。
f.于是依次推得到
| ? | ? | a | b | c |
| ? | 0 | 1 | 2 | 3 |
| a | 1 | A處?0 | D處?1 | G處?2 |
| b | 2 | B處?1 | E處?0 | H處?1 |
| e | 3 | C處?2 | F處?1 | I處?1 |
?
I 處:?表示 abc 和 abe 有1個需要編輯的操作( c 替換成 e )。這個是需要計算出來的。
同時,也獲得一些額外的信息:
A處:?表示a????? 和a ? ? ? 需要有0個操作。字符串一樣
B處:?表示ab??? 和a ? ? ? 需要有1個操作。
C處:?表示abe? 和a ? ? ? 需要有2個操作。
D處:?表示a????? 和ab ? ? 需要有1個操作。
E處:?表示ab??? 和ab ? ? 需要有0個操作。字符串一樣
F處:?表示abe? 和ab ? ? 需要有1個操作。
G處:?表示a????? 和abc?? 需要有2個操作。
H處:?表示ab ?? 和abc ? 需要有1個操作。
I處:?表示abe ? 和abc ?? 需要有1個操作。
g.計算相似度
先取兩個字符串長度的最大值 maxLen,用 1-(需要操作數(shù) 除 maxLen),得到相似度。
例如 abc 和 ?abe ?一個操作,長度為 3 ,所以相似度為 1-1/3=0.666 。
?
以上就是整個算法的推導(dǎo)過程,但是至于為什么能算出相似度,還是不太懂。而且我發(fā)現(xiàn)這個算法有個很坑的地方,就是有時候根據(jù)算法推算出的結(jié)果,會和我們想象中的不一樣:
例如:字符串 abcd 和字符串 def ,根據(jù)算法算出來的相似度為 0,可是明明是由一個相同字符 d 的,至少應(yīng)該是有一定相似度,即使很相似度很低,但是也不應(yīng)該為0才對。但是字符串 abcd 和字符串 aert ,同樣是只有一個相同字符 a ,但是根據(jù)算法算出來的相似度卻為 0.25 。
根據(jù)最開始對算法的介紹,使用替換、刪除、插入這三種操作方式,字符串 abcd 和字符串 aert 最少需要 3 步就能完成轉(zhuǎn)變,而字符串 abcd 和字符串 def 卻最少需要4步才能完成轉(zhuǎn)變,兩個字符串的最大長度才為 4 ,而完成轉(zhuǎn)換卻至少需要 4 步,相似度為 0 好像也能說的通,但是從表面來看,明明有一個相同的字符d,相似度為0,讓我覺得很怪異,所以我認(rèn)為再使用的時候需要慎重。
?
下面是我的 C# 代碼實現(xiàn):
1 using UnityEngine; 2 using System.Collections; 3 using System; 4 5 public class EditorDistance 6 { 7 /// <summary> 8 /// 比較兩個字符串的相似度,并返回相似率。 9 /// </summary> 10 /// <param name="str1"></param> 11 /// <param name="str2"></param> 12 /// <returns></returns> 13 public static float Levenshtein(string str1, string str2) 14 { 15 char[] char1 = str1.ToCharArray(); 16 char[] char2 = str2.ToCharArray(); 17 //計算兩個字符串的長度。 18 int len1 = char1.Length; 19 int len2 = char2.Length; 20 //建二維數(shù)組,比字符長度大一個空間 21 int[,] dif = new int[len1 + 1, len2 + 1]; 22 //賦初值 23 for (int a = 0; a <= len1; a++) 24 { 25 dif[a, 0] = a; 26 } 27 for (int a = 0; a <= len2; a++) 28 { 29 dif[0, a] = a; 30 } 31 //計算兩個字符是否一樣,計算左上的值 32 int temp; 33 for (int i = 1; i <= len1; i++) 34 { 35 for (int j = 1; j <= len2; j++) 36 { 37 if (char1[i - 1] == char2[j - 1]) 38 { 39 temp = 0; 40 } 41 else 42 { 43 temp = 1; 44 } 45 //取三個值中最小的 46 dif[i, j] = Min(dif[i - 1, j - 1] + temp, dif[i, j - 1] + 1, dif[i - 1, j] + 1); 47 } 48 } 49 //計算相似度 50 float similarity = 1 - (float)dif[len1, len2] / Math.Max(len1, len2); 51 return similarity; 52 } 53 54 /// <summary> 55 /// 求最小值 56 /// </summary> 57 /// <param name="nums"></param> 58 /// <returns></returns> 59 private static int Min(params int[] nums) 60 { 61 int min = int.MaxValue; 62 foreach (int item in nums) 63 { 64 if (min > item) 65 { 66 min = item; 67 } 68 } 69 return min; 70 } 71 }?
轉(zhuǎn)載于:https://www.cnblogs.com/cuihongyu3503319/p/10184031.html
總結(jié)
以上是生活随笔為你收集整理的字符串相似度算法——Levenshtein Distance算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Canvas Clock
- 下一篇: [LeetCode]LRU Cache有