[动态规划]最长公共子串长度问题

来源:互联网 发布:mac foxmail 导入邮件 编辑:程序博客网 时间:2024/06/06 03:15

题目来自于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;}elseF[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");}


0 0
原创粉丝点击