1. Levenshtein Distance
該演算法又稱之為 "編輯距離",用於計算兩個字串的相似程度。原理很簡單,就是返回將第一個字串轉換(刪除、插入、替換)成第二個字串的編輯次數。次數越少,意味著字串相似性越高。
演算法原理:Wikipedia - Levenshtein distance 本文摘自:http://www.rainsts.net/article.asp?id=767
Step1:
人 民 共 和 時 代 0, 0, 0, 0, 0, 0, 0 中 1, 0, 0, 0, 0, 0, 0 華 2, 0, 0, 0, 0, 0, 0 人 3, 0, 0, 0, 0, 0, 0 民 4, 0, 0, 0, 0, 0, 0 共 5, 0, 0, 0, 0, 0, 0 和 6, 0, 0, 0, 0, 0, 0 國 7, 0, 0, 0, 0, 0, 0
Step2:
人 民 共 和 時 代 0, 1, 2, 3, 4, 5, 6 中 1, 0, 0, 0, 0, 0, 0 華 2, 0, 0, 0, 0, 0, 0 人 3, 0, 0, 0, 0, 0, 0 民 4, 0, 0, 0, 0, 0, 0 共 5, 0, 0, 0, 0, 0, 0 和 6, 0, 0, 0, 0, 0, 0 國 7, 0, 0, 0, 0, 0, 0
Step3:
人 民 共 和 時 代 0, 1, 2, 3, 4, 5, 6 中 1, 1, 2, 3, 4, 5, 6 華 2, 2, 2, 3, 4, 5, 6 人 3, 2, 3, 3, 4, 5, 6 民 4, 3, 2, 3, 4, 5, 6 共 5, 4, 3, 2, 3, 4, 5 和 6, 5, 4, 3, 2, 3, 4 國 7, 6, 5, 4, 3, 3, 4
演算法實現: public static int LevenshteinDistance(string s1, string s2) { if (s1 == s2) return 0; else if (String.IsNullOrEmpty(s1)) return s2.Length; else if (String.IsNullOrEmpty(s2)) return s1.Length;
var m = s1.Length + 1; var n = s2.Length + 1; var d = new int[m, n];
// Step1 for (var i = 0; i < m; i++) d[i, 0] = i;
// Step2 for (var j = 0; j < n; j++) d[0, j] = j;
// Step3 for (var i = 1; i < m; i++) { for (var j = 1; j < n; j++) { var cost = s1[i - 1] == s2[j - 1] ? 0 : 1;
var deletion = d[i - 1, j] + 1; var insertion = d[i, j - 1] + 1; var substitution = d[i - 1, j - 1] + cost;
d[i, j] = Math.Min(Math.Min(deletion, insertion), substitution); } }
return d[m - 1, n - 1]; } 2. LCS
LCS (Longest Common Subsequence) 演算法用於找出兩個字串最長公用子串。
演算法原理:
(1) 將兩個字串分別以行和列組成矩陣。 (2) 計算每個節點行列字元是否相同,如相同則為 1。 (3) 通過找出值為 1 的最長對角線即可得到最長公用子串。
人 民 共 和 時 代 中 0, 0, 0, 0, 0, 0 華 0, 0, 0, 0, 0, 0 人 1, 0, 0, 0, 0, 0 民 0, 1, 0, 0, 0, 0 共 0, 0, 1, 0, 0, 0 和 0, 0, 0, 1, 0, 0 國 0, 0, 0, 0, 0, 0
為進一步提升該演算法,我們可以將字元相同節點(1)的值加上左上方(d[i-1, j-1])的值,這樣即可獲得最大公用子串的長度。如此一來只需以行號和最大值為條件即可截取最大子串。
人 民 共 和 時 代 中 0, 0, 0, 0, 0, 0 華 0, 0, 0, 0, 0, 0 人 1, 0, 0, 0, 0, 0 民 0, 2, 0, 0, 0, 0 共 0, 0, 3, 0, 0, 0 和 0, 0, 0, 4, 0, 0 國 0, 0, 0, 0, 0, 0
演算法實現: public static string LCS(string s1, string s2) { if (s1 == s2) return s1; else if (String.IsNullOrEmpty(s1) || String.IsNullOrEmpty(s2)) return null;
var d = new int[s1.Length, s2.Length];
var index = 0; var length = 0;
for (int i = 0; i < s1.Length; i++) { for (int j = 0; j < s2.Length; j++) { // 左上方值 var n = i - 1 >= 0 && j - 1 >= 0 ? d[i - 1, j - 1] : 0;
// 當前節點值 = "1 + 左上方值" : "0" d[i, j] = s1[i] == s2[j] ? 1 + n : 0;
// 如果是最大值,則記錄該值和行號 if (d[i, j] > length) { length = d[i, j]; index = i; } } }
return s1.Substring(index - length + 1, length); } |