我通过在对后缀列表进行排序后比较字符串的后缀来实现解决方案。有没有比这段代码更好的线性时间算法?
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
void preCompute(string input[],string s)
{
int n = s.length();
for(int i=0; i<n; i++)
input[i] = s.substr(i,n);
}
string LongestCommonSubString(string first,string second)
{
int n = min(first.length(),second.length());
for(int i=0; i<n; i++)
if(first[i]!=second[i])
return first.substr(0,i);
return first.substr(0,n);
}
string lrs(string s)
{
int n = s.length();
string input[n];
preCompute(input,s);
sort(input, input+n);
string lrs = "";
for(int i=0; i<n-1; i++)
{
string x = LongestCommonSubString(input[i],input[i+1]);
if(x.length()>lrs.length())
{
lrs = x;
}
}
return lrs;
}
int main()
{
string input[2] = {"banana","missisipi"};
for(int i=0;i<2;i++)
cout<<lrs(input[i])<<endl;
return 0;
}
我找到了一个非常好的资源来解决这个问题。见here
答案 0 :(得分:6)
您可以在线性时间内构建后缀树(请参阅this)。最长的重复子串对应于最深的内部节点(当我说最深的时候,我的意思是来自根的路径具有最大字符数,而不是最大边数)。原因很简单。内部节点对应于多个后缀中出现的后缀(即子串)的前缀。
实际上,这是相当复杂的。所以你采取的方法是足够好的。我可以提出一些修改建议: