2017-03-08 586 views
2

假設我有一個字符串列表,它們是相似的。我想弄清楚所有這些字符串的共同部分或特徵。是否有一種已知的方法可以找出與給定集合中所有字符串最相似的字符串,並且不屬於該集合?編輯字符串距編輯距離最短的字符串

例如,如果我有以下組:

Hello 
Hell 
Help 
Hepl 

'赫爾' 給出的一個2,1,1,1 Levenshtein距離。目前我正在考慮以不同的子字符串爲基礎,並計算距離(我的集合相當小,所以粗暴的強制不會成爲問題),但是這種解決方案並沒有發現字符串,它本質上不是任何給定字符串的子字符串集合,但可能是最優的解決方案(例如解決方案是兩個子串共軛的情況)。

任何與此有關的線索將不勝感激。

+0

我從未有過這樣的代碼,但[哈羅 - 溫克勒距離(https://en.wikipedia.org/wiki/Jaro%E2%80% 93Winkler_distance) –

+0

「Hell」比「Hel」更好,因爲前者給出1,1,1,1的Levenstein距離。 – user31264

+0

嘗試使用具有扁平字母矩陣(?)的clustal算法進行多重比對,並調整空位罰分。 –

回答

1

你說蠻力是可以接受的:-)。經典的方法是廣度優先搜索。對於列表中的每個字符串,您都會生成編輯距離爲1的所有字符串,從那些距離爲2的字符串等等。對於每個給定的字符串,你會得到一個變異字符串樹。在每一輪(距離)之後,檢查每棵樹是否有一個共同的字符串。

僞代碼爲Levenshtein距離:

alphabet = "abcd..." 
starters = "Hello", "Hell", "Help", "Hepl" 
relatives = set() 
distance = 0 
for word in starters 
    trees[word][distance] = word 

while len(relatives) == 0 
    distance++ 
    for tree in trees 
     for word in tree[distance-1] 
      for pos in range(len(word)) 
       new_word = word.erase(pos) 
       if new_word not in tree 
        tree[distance].insert(new_word) 
        dict[new_word] += 1 
        if dict[new_word] == len(starters) 
         relatives.insert(new_word) 
      for pos in range(len(word)) 
       for letter in alphabet 
        new_word = word.replace(pos, letter) 
        if new_word not in tree: 
         tree[distance].insert(new_word) 
         dict[new_word] += 1 
         if dict[new_word] == len(starters) 
          relatives.insert(new_word) 
      for pos in range(len(word) + 1): 
       for letter in alphabet 
        new_word = word.insert(pos, letter) 
        if new_word not in tree 
         tree[distance].insert(new_word) 
         dict[new_word] += 1 
         if dict[new_word] == len(starters) 
          relatives.insert(new_word) 
print relatives 
+0

非常整潔的解決方案。唯一需要注意的是,如果我的琴絃長度很長,並且絃線很小,這將永遠需要找到解決方案。看看我能不能想到優化這種情況。 – Ulrich

+0

@Ulrich:你說蠻力是可以接受的:-)。如果這是關於脫氧核糖核酸字符串,您從馬爾科姆得到一個好指針。什麼是字符串長度?爲什麼常用字符串很小?請優化您的問題以表示您的實際要求。 – stefan