所以我有一个数组,我必须搜索单词
数组:
0 1 2 3 4 5 6 7 8 9 10 11
text g t c a n d l e t j a q
钥匙:
2 can
2 candle
3 a
3 an
3 and
6 let
10 a
该数字是从被搜索数组的开头开始的偏移量,该字符串是在该偏移量处找到的字典中的单词。请注意,多个单词可以从相同的偏移量开始,并且可以在多个位置找到相同的单词。另请注意,单词可以重叠。
这是我写的代码:
public ArrayList<Location> findWords(String[] dictionary, String text) {
int keyLength = text.length();
int dtLength = dictionary.length;
ArrayList<Location> results;
results = new ArrayList<>();
for (int k = 0; k < keyLength; k++) {
for (int d = 0; d < dtLength; d++) {
if (dthasKey(dictionary[d], text, k)) {
Location loc = new Location(k, dictionary[d]);
results.add(loc);
}
}
}
return results;
}
private boolean dthasKey(String key, String text, int pos) {
for (int i = 0; i < key.length(); i++) {
if (key.length() >= text.length() - pos)
return false;
while (key.charAt(i) != text.charAt(pos + i)) {
return false;
}
}
return true;
}
我想知道是否有更好的解决方案来解决这个问题。如果你们这些人也可能提供最糟糕的时间复杂性,那就太棒了。我写的那个是:
O(k*n*m)
其中m是。的大小
字典,n是文本的大小,k是长度
最长的词。
答案 0 :(得分:2)
问题的标准解决方案是使用Aho-Corasick string matching algorithm,它从字典中构建自动机,然后可以快速查找传递给它的字符串中的所有单词。 Google搜索揭示了许多Java实现。
构建自动机是O(n),其中n是字典所有单词中的字符数。但这是一次性成本。您可以使用该自动机在多个文档中搜索单词。
搜索单词的文件是O(m + z),其中m是文档中的字符数,z是找到的匹配数。
我不知道Aho-Corasick是否是最快的算法,但速度非常快。并且现有的Java实现将是一个很大的优势。但实施起来并不是特别困难。原始论文Efficient String Matching: an Aid to Bibliographic Search是非常易读的,虽然它可能需要在“点击”之前再次阅读,思考和阅读。并且伪代码示例足够详细,您可以将它们用作实现的基础。我为使用该文档作为我唯一参考的文章创建了C# implementation。
答案 1 :(得分:0)
你可以为每个单词(只接受那个单词)创建一个自动机,然后同时在所有自动机中运行给定的文本,这将最终为O(m * k ^ 2 + n)