以下題目來自阿里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的一個公共子串。
程序輸出: