題目來自於2014.8.29阿里在線筆試題:給定一個query和一個text,均由小寫字母組成。要求在text中找出以同樣的順序連續出現在query中的最長連續字母序列的長度。例如, query爲“acbac”,text爲“acaccbabb”,那麼text中的“cba”爲最長的連續出現在query中的字母序列,因此,返回結果應該爲其長度3。請注意程序效率。
仔細分析這道題,發現就是求query和text的最長公共子串長度,是經典的動態規劃問題。
設F(i,j)表示以query[i]和text[j]爲結尾的公共子串長度,如果query[i]!=text[j],即兩個字符不等,顯然不會有以兩者爲共同結尾的子串,因此F(i,j)=0;如果query[i]==text[j],即兩個字符相等,就應該判斷兩者前一個字符是否相等,如果不等則說明只有這兩個字符是公共子串,因此F(i,j)=1,如果相等,公共子串長度應爲前一個字符的公共子串長度加1,因此F(i,j)=F(i-1,j-1)+1。
綜上可知狀態轉移方程爲:
F(i,j) = 0 ( query[i]!=text[j] )
= F(i-1,j-1)+1 (query[i]==text[j] )
實際編程時,可開闢Q*T大小的二維數組存儲計算結果,再從所有結果中取出最大值即可。
複雜度分析:Q爲query長度,T爲text長度,需要把每個字符兩兩進行比較,時間複雜度爲O(Q*T),需要存儲所有字符的比較結果,空間複雜度爲O(Q*T)
代碼如下:
/*
給定一個query和一個text,均由小寫字母組成。要求在text中找出以同樣的順序連續出現在
query中的最長連續字母序列的長度。例如, query爲“acbac”,text爲“acaccbabb”,那麼text
中的“cba”爲最長的連續出現在query中的字母序列,因此,返回結果應該爲其長度3。請注意程
序效率。
*/
#include <iostream>
#include <string>
using namespace std;
int findMaxLenDP( const string& query , const string& text )
{
int Qlen = query.length();
int Tlen = text.length();
int** F = new int*[Qlen];//二維數組,存儲所有公共子串長度
for( int i=0 ; i<Qlen ; i++ )
F[i] = new int[Tlen];
for( int i=0 ; i<Qlen ; i++ )
{
for( int j=0 ; j<Tlen ; j++ )
F[i][j]=0;
}
//初始化第一行和第一列
for( int i=0 ; i<Qlen ; i++ )
{
if( query[i] == text[0] )
F[i][0] = 1;
}
for( int j=0 ; j<Tlen ; j++ )
{
if( text[j] == query[0] )
F[0][j] = 1;
}
int maxSublen = 0;//存儲最大公共子串長度
for( int i=1 ; i<Qlen ; i++ )
{
for( int j=1 ; j<Tlen ; j++ )
{
//狀態轉移方程
if( query[i] == text[j] )
{
F[i][j] = F[i-1][j-1]+1;
maxSublen = F[i][j]>maxSublen ? F[i][j] : maxSublen;
}
else
F[i][j] = 0;
}
}
for( int i=0 ; i<Qlen ; i++ )
delete[] F[i];
delete[] F;
return maxSublen;
}
int main()
{
cout << findMaxLenDP( "acbac" , "acaccbabb" ) << endl;
system("pause");
}