以下题目来自阿里2015校园招聘、牛客网。
给定一个query和一个text,均由小写字母组成。要求在text中找出以同样的顺序连续出现在query中的最长连续字母序列的长度。例如,query为 "acbac",text为"acaccbabb",那么text中的"cba"为最长的连续出现在query中的字母序列,因此,返回结果应该为其长度3。请注意程序效率。
假设text的长度为m,query的长度为n,n小于等于m。
n中 子串的长度的范围为1到n。
长度为1的子串个数为n
长度为2的子串个数为n-1
……
长度为i的子串个数为n-i+1
……
长度为n的子串个数为1
m中子串的长度范围为1到m
长度为1的子串个数为m
长度为2的子串个数为m-1
……
长度为i的子串个数为m-i+1
……
长度为n的子串个数为1
所以当子串的长度为i,长度为i的n的子串与长度为i的m的子串的组合数为
(m-i+1)*(n-i+1)。
因为n小于等于m。所以总的子串组合数为
这种逐个子串比较的方法时间复杂度较高。
以下程序参考牛客网大明白网友程序。
#include<iostream>
using namespace std;
#include<vector>
void printLongestSubString(vector<vector<int> > &temp,char *query,int locy,int locx)
{
if(locy<0||locx<0||temp[locy][locx]==0)
return;
printLongestSubString(temp,query,locy-1,locx-1);
cout<<query[locy];
}
int getLongestSubString(char *query,char *text)
{
if(query==NULL||text==NULL)
return 0;
int imax=INT_MIN;
int m=strlen(query);
int n=strlen(text);
int locx=0;
int locy=0;
vector<vector<int> > temp(m,vector<int>(n,0));
for(int i=0;i<m;i++)//行
{
for(int j=0;j<n;j++)//列
{
if(query[i]==text[j])
{
if(i==0||j==0)
{
temp[i][j]=1;
}
else
{
temp[i][j]=temp[i-1][j-1]+1;
}
if(temp[i][j]>imax)
{
imax=temp[i][j];
locx=j;
locy=i;
}
}
}
}
/*输出最长公共子串的第一种方法*/
int locy1=locy;
int locx1=locx;
printLongestSubString(temp,query,locy1,locx1);//递归输出最长公共子串
cout<<endl;
/*输出最长公共子串的第二种方法*/
char *output1=new char[imax+1];
int index=imax-1;
while(locx>=0&&locy>=0&&temp[locy][locx]!=0)//反转最长公共子串
{
output1[index--]=query[locy];
locy--;
locx--;
}
output1[imax]='\0';
puts(output1);
for(int i=0;i<m;i++)//输出vector中的值
{
for(int j=0;j<n;j++)
{
cout<<temp[i][j]<<" ";
}
cout<<endl;
}
return imax;
}
int main()
{
char query[]="acbac";
char text[]="acaccbabb";
cout<<getLongestSubString(query,text);
return 0;
}
图中y轴为query字符串,x轴为text字符串,图中红色为方格所对应y轴字符为text与query的最长公共字串cba,蓝色方格所对应y轴字符为ac,也是query与text的一个公共子串。
程序输出: