我刚接触到一个采访问题: 查找给定字符串中具有最小大小2的所有重复子字符串。 该算法应该是有效的。
以上给出了上述问题的代码,但效率不高。
#include <iostream>
#include <algorithm>
#include <iterator>
#include <set>
#include <string>
using namespace std;
int main()
{
typedef string::const_iterator iterator;
string s("ABCFABHYIFAB");
set<string> found;
if (2 < s.size())
for (iterator i = s.begin() + 1, j = s.end(); i != j; ++i)
for (iterator x = s.begin(); x != i; ++x)
{
iterator tmp = mismatch(i, j, x).second;;
if (tmp - x > 1)
found.insert(string(x, tmp));
}
copy(found.begin(), found.end(),ostream_iterator<string>(cout, "\n"));
}
我的问题是,是否有任何数据结构可以及时实现上述问题 O(N)的复杂性?
如果您的答案是后缀树或哈希,请详细说明。
答案 0 :(得分:5)
如果分析字符串"AAAAAAAAAAAAAA"
的输出,则其中有O(n²)个字符,因此算法至少为O(n²)。
要实现O(n²),只需为s的每个后缀构建suffix tree(indices [1..n],[2..n],[3..n],..., [n..n])。如果其中一个字符串没有自己的结束节点,只计算每个节点的使用频率并不重要。
最后,迭代计数&gt; 1的每个节点并打印其路径。
答案 1 :(得分:1)
这只是一个疯狂的想法,但值得一试(但是,它会消耗O(N)内存,其中N是主字符串的长度)。算法不是O(N),但也许可以优化。
这个想法是,你不想经常进行字符串比较。您可以收集读取数据的哈希值(例如读取字符的ASCII码之和)并比较哈希值。如果哈希值相等,则字符串可能相等(稍后必须检查)。例如:
ABCAB
A -> (65)
B -> (131, 66)
C -> (198, 133, 67)
A -> (263, 198, 132, 65)
B -> (329, 264, 198, 131, 66)
因为您只对2个长度值感兴趣,所以必须省略最后一个值(因为它总是对应于单个字符)。
我们看到两个相等的值:131和198. 131代表AB并显示该对,但198代表ABC和BCA,必须通过人工检查拒绝。
这只是想法,而不是解决方案本身。可以扩展散列函数以考虑子字符串(或序列结构)中字符的位置。可以改变散列值的存储方法以提高性能(但是增加内存使用的成本)。
希望我能帮助一点:)
答案 2 :(得分:0)
我不知道后缀树如何能够获得所有重复的子串,字符串“mississippi”构建后缀树如下:
对不起,我明白了。 “最后,迭代计数&gt; 1的每个节点并打印其路径。” “count”是这个子节点的数量tree-->|---mississippi m..mississippi
|
|---i-->|---ssi-->|---ssippi i .. ississippi
| | |
| | |---ppi issip,issipp,issippi
| |
| |---ppi ip, ipp, ippi
|
|---s-->|---si-->|---ssippi s .. ssissippi
| | |
| | |---ppi ssip, ssipp, ssippi
| |
| |---i-->|---ssippi si .. sissippi
| |
| |---ppi sip, sipp, sippi
|
|---p-->|---pi p, pp, ppi
|
|---i p, pi
--- Suffix Tree for "mississippi" ---