我有一个java列表(如果有必要,它可能是一个地图)有很多字符串。
我希望以有效的方式为另一个给定字符串找到最相似的字符串。
我想我应该使用Levenshtein距离,但我不想遍历所有列表。
您是否认为将主列表划分为具有公共前缀的某些部分是个好主意?
然后我会有一个地图,其中前缀为关键字,列表为值:
通过这种方式,我可以快速搜索与搜索到的字符串相同的字符串。然后我可以仅对某些字符串应用Levenshtein距离而不是所有主列表。
这是个好主意吗?感谢
答案 0 :(得分:0)
您可以计算每个条目的soundex代码,并将soundex映射到原始单词列表。 Soundex是一个缩减代码,用于获得类似发声单词的单个键。
Map<String, Set<String>> soundexToWords = ...
for (String word : words) {
String sdex = soundex(word);
Set<String> similarWords = soundexToWords.get(sdex));
if (similarWords == null) {
similarWords = new HashSet<>();
soundexToWords.put(sdex, similarWords);
}
similarWords.add(word);
}
Set<String> similarWords(String word) {
return soundexToWords.get(soundex(word));
}
Soundex通常用于一种语言,比如说英语,特别是对于英语而言,它非常简单。
答案 1 :(得分:0)
最简单的解决方案是先在List
上致电List
。现在,您的列表按lexicographical order排序。接下来,在列表上执行二进制搜索以查找前缀所在的位置。返回的索引基本上为您提供了最相似的单词的位置。
然后,您可以通过将前缀映射到索引来构建地图,这样您就可以根据需要检索整个List
的子集,或者您可以在地图中缓存子集本身。此子集是一个列表,从整个O(m)
中的索引开始,其元素具有递减的相似性。您可以将停止索引微调为第一个字母增量或类似的东西。
最佳解决方案是查看trie数据结构。 trie支持m
个查询,其中O(1)
是您要搜索的前缀的长度。这会占用远远少于空间并避免哈希冲突。虽然您的地图理论上支持O(n^2)
个查询,但如果您明确存储每个列表,则构建时间为O(n)
。如果存储索引,则构建时间是线性的,但每个请求都是{{1}}。
答案 2 :(得分:0)
public List<String> similarWords(String word, List<String> allWords){
List<String> similarWordList = new ArrayList<>();
for(String currentWord : allWords){
if(currentWord.contains(word)){
similarWordList.add(currentWord);
}
}
return similarWordList;
}