Java:查找类似的字符串

时间:2015-07-14 15:54:39

标签: java performance similarity levenshtein-distance

我有一个java列表(如果有必要,它可能是一个地图)有很多字符串。

  • 列表(你好,地狱,汽车,卡通,...)

我希望以有效的方式为另一个给定字符串找到最相似的字符串。

我想我应该使用Levenshtein距离,但我不想遍历所有列表。

您是否认为将主列表划分为具有公共前缀的某些部分是个好主意?

然后我会有一个地图,其中前缀为关键字,列表为值:

  • hel - >列表(你好,地狱,...)
  • car - >列表(汽车,卡通,...)

通过这种方式,我可以快速搜索与搜索到的字符串相同的字符串。然后我可以仅对某些字符串应用Levenshtein距离而不是所有主列表。

这是个好主意吗?感谢

3 个答案:

答案 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;
}