题目描述:
给定两个字符串,求解两者的最长重复子串(长度),有的最长重复子串不是唯一的,给出一个最长的即可。
例:abfjgk anrfgll
两者的最长重复子串为 afg (3)。
算法点睛思想:
str1前x子串与str2前y子串长度:
C
(
x
,
y
)
=
{
C
(
x
−
1
,
y
−
1
)
+
1
,
s
t
r
1
[
x
]
=
s
t
r
2
[
y
]
m
a
x
[
C
(
x
−
1
,
y
)
,
C
(
x
,
y
−
1
)
]
,
s
t
r
1
[
x
]
≠
s
t
r
2
[
y
]
C(x,y)= \begin{cases} C(x-1,y-1)+1, str1[x]=str2[y] \\ max[C(x-1,y),C(x,y-1)], str1[x] \ne str2[y] \end{cases}
C(x,y)={C(x−1,y−1)+1,str1[x]=str2[y]max[C(x−1,y),C(x,y−1)],str1[x]̸=str2[y]在这个思想的基础上,计算长度的同时记录下当前的最大长度是从哪个最大长度得到的,以便最终的回溯。
举个栗子:
C++代码:
// An highlighted block
#include <iostream>
using namespace std;
//求最长公共子串
int longestCommonSubsequence(char * text1, int n, char * text2, int m);
int main()
{
char text1[]="aaaasnfksd";
char text2[]="asnflss";
int n = sizeof(text1)/sizeof(char)-1;
int m = sizeof(text2)/sizeof(char)-1;
cout<<longestCommonSubsequence(text1, n, text2, m)<<endl;
return 0;
}
int longestCommonSubsequence(char * text1, int n, char * text2, int m){
//标注此前两子串的“最长重复子串长度”
int* len=new int[(m+1)*(n+1)];
//标注如何得到的,从左上方0、上方1、左方2
int* trace=new int[(m+1)*(n+1)];
memset(len,0,sizeof(int)*(m+1)*(n+1));
memset(trace,0,sizeof(int)*(m+1)*(n+1));
for(int i=1;i<=m;++i)
{
for(int j=1;j<=n;++j)
{
if(text1[j-1]==text2[i-1])
{
len[i*(n+1)+j]=len[(i-1)*(n+1)+(j-1)]+1;
trace[i*(n+1)+j]=0;
}
else
{
if(len[(i-1)*(n+1)+(j)]>=len[(i)*(n+1)+(j-1)])
{//上大
len[i*(n+1)+j]=len[(i-1)*(n+1)+(j)];
trace[i*(n+1)+j]=1;
}
else
{//左大
len[i*(n+1)+j]=len[(i)*(n+1)+(j-1)];
trace[i*(n+1)+j]=2;
}
}
}
}
int length = len[m*(n+1)+n];
int x=m;
int y=n;
char* res = new char[len[m*(n+1)+n]];
int i=0;
while(i<len[m*(n+1)+n])
{
if(trace[x*(n+1)+y]==0)
{
x-=1;
y-=1;
res[(len[m*(n+1)+n]-1)-i]=text1[y];
i++;
}
else if(trace[x*(n+1)+y]==1)//上
x-=1;
else//左
y-=1;
}
for(int i=0;i<len[m*(n+1)+n];++i)
cout<<res[i]<<",";
cout<<endl;
delete[] len;
delete[] trace;
delete[] res;
return length;
}
空间上还有优化空间,待研究。