我们如何在O(n)时间内实现“子串匹配”?

时间:2011-11-17 09:06:45

标签: java string algorithm language-agnostic

我的作业需要读取大量的随机输入文件,例如:

Adana 
Izmir Adnan Menderes Apt
Addis Ababa
Aden
ADIYAMAN
ALDAN
Amman Marka Intl Airport
Adak Island
Adelaide Airport
ANURADHAPURA
Kodiak Apt
DALLAS/ADDISON
Ardabil 
ANDREWS AFB
etc..

如果我指定一个搜索词,程序应该找到子串出现的行。例如,如果搜索词是“uradha”,则该程序应显示ANURADHAPURA。如果搜索字词为“机场”,则该程序应显示Amman Marka Intl Airport, Adelaide Airport

来自作业规范的引用:“你要对这个应用程序进行编程,同时考虑到效率,好像涉及大量的数据和处理......”

我可以使用循环轻松实现此功能,但性能将为O(n)。我正在考虑使用trie,但它似乎只有在子串从索引0开始时才有效。

我想知道哪些解决方案的性能优于O(n)?

5 个答案:

答案 0 :(得分:11)

Here's将O(n)作为最坏情况下的时间复杂度。

顺便说一下,您应该为此链接添加书签:http://www-igm.univ-mlv.fr/~lecroq/string/

答案 1 :(得分:10)

您可以查看Boyer-Moore string search algorithmKnuth-Morris-Pratt string search algorithm。它们具有良好的渐近性能,但我不知道一个算法不需要至少读取一次(几乎全部)输入和输出字符串,因此会比O(n)性能更好(其中n是输入的大小。)

答案 2 :(得分:3)

我的直觉说你正在思考一个特里的正确轨道,你可能想要查看Wikipedia上与Suffix Tree链接的特里页面的这一部分,以获得更多想法。不幸的是,O(n)的想法。

答案 3 :(得分:3)

输入文本几乎是静态内容(或者不经常添加值,并且值被添加到输入源的末尾),但搜索通常可以尝试跟随(可能与trie相同)

1)您将阅读所有文本(并且还会更新然后添加新元素)并准备索引表(符号映射到匹配发生的坐标(行或位置))

'aa' - 1, 15, 27... 
'as' - 1, 15, 17...
'ba' - 2, 3, 15...
...

2)首先通过前2个符号搜索索引表中的坐标

3)然后继续按坐标

搜索输入文本

答案 4 :(得分:1)

Boyer-Moore和一些使用变体的算法可以实现" O(n / m)" (其中n是干草堆的长度,m是针的长度)某些针的最佳情况表现,但这取决于针上的非重复标准,这对于任意大的m是不可能满足的(例如m得到比字符集大小大得多的东西,甚至使最好的情况更像O(n / 256),因此O(n)。仍然在现实世界的应用中,m往往很小,针往往不是病理周期性的,BM及其堂兄弟表现得非常好。

我个人推荐"双向"算法(在glibc实现中使用类似BM的扩展),因为它保证了O(n)边界和恒定的工作空间。