算法题9 动态规划之最长公共子序列&最长公共子串

题目

  如果字符串1的所有字符按其在字符串中的顺序出现在另外一个字符串2中,则字符串1称之为字符串2的子序列。

  注意,并不要求子子序列(字符串1)的字符必须连续出现在字符串2中。

  请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子序列。

  例如:输入两个字符串BDCABA和ABCBDAB,字符串BCBA和BDAB都是是它们的最长公共子序列,则输出它们的长度4,并打印任意一个子序列。

分析

  本问题是典型的动态规划问题,子字符串的最优解为字符串提供了决策依据。有两个字符串str1和str2,设c[i,j]为子串str1[0-i]和str2[0-j]的最长公共子序列的长度,

  如果str1[i]=str2[j],则c[i,j]=c[i-1,j-1]+1;

  如果str1[i]!=str2[j],则c[i,j]要么等于str1[0,i-1]和str2[0,j]的最长公共子序列的长度,要么等于str1[0,i]和str2[0,j-1]的最长公共子序列的长度,取两者的最大值即是c[i,j]

  如图一个示例

        

  状态转移方程:

  c[0,j]=0;

  c[i,0]=0;

  c[i,j]=c[i-1,j-1]+1, 若str1[i]=str2[j];

  c[i,j]=max{c[i-1,j],c[i,j-1]}

代码

 1 int Lcslen(char* stra,char* strb,int** c)
 2 {
 3     int len_a=strlen(stra);
 4     int len_b=strlen(strb);
 5 
 6     for(int i=1;i<=len_a;i++)
 7     {
 8         for(int j=1;j<=len_b;j++)
 9         {
10             if(stra[i-1]==strb[j-1])
11             {
12                 c[i][j]=c[i-1][j-1]+1;
13             }else
14             {
15                 c[i][j]=(c[i][j-1]>c[i-1][j])?c[i][j-1]:c[i-1][j];
16             }
17         }
18     }
19 
20     return c[len_a][len_b];
21 }
22 
23 void lcs(char* stra,char* strb)
24 {
25     if(stra==NULL||strb==NULL)
26         return;
27     int len_a=strlen(stra);
28     int len_b=strlen(strb);
29     int** c=new int*[len_a+1];
30     for (int i=0;i<=len_a;i++)
31     {
32         c[i]=  new int[len_b+1]();
33     }
34 
35     int k=Lcslen(stra,strb,c);
36 
37     char* lcs=new char[k];
38 
39     int i=len_a+1;
40     int j=len_b+1;
41     while(k>=0)
42     {
43         if(c[i][j]==c[i][j-1])
44         {
45             j--;
46         }else if(c[i][j]==c[i-1][j])
47         {
48             i--;
49         }else if(c[i][j]==c[i-1][j-1])
50         {
51             lcs[k--]=stra[i-1];
52             i--;
53             j--;
54         }
55     }
56 
57     for (int i=0;i<=len_a;i++)
58     {
59         delete[] c[i]; 
60     }
61     delete[] c;
62 }

 

动态规划之最长公共子串

  本题和上题的区别是子串要求是连续的。那么当str1[i]!=str2[j]的时候,前面的公共子串到此结束,c[i,j]重新等于0,开始寻找下一个公共子串。

  状态转移方程式变为:

  c[0,j]=0;

  c[i,0]=0;

  c[i,j]=c[i-1,j-1]+1, 若str1[i]==str2[j];

  c[i,j]=0, 若str1[i]!=str2[j]

  最大子串长度max_dis=max{c[i][j]}

代码

 1 int ContinuousLCS(char* stra,char* strb)
 2 {
 3     if(stra==NULL||strb==NULL)
 4         return -1;
 5 
 6     int len_a=strlen(stra);
 7     int len_b=strlen(strb);
 8 
 9     //new space of int[][]
10     int** c=new int*[len_a+1];
11     for (int i=0;i<=len_a;i++)
12     {
13         c[i]=  new int[len_b+1]();
14     }
15 
16     int max_dis=0,index=0;
17     for(int i=1;i<=len_a;i++)
18     {
19         for(int j=1;j<=len_b;j++)
20         {
21             if(stra[i-1]==strb[j-1])
22             {
23                 c[i][j]=c[i-1][j-1]+1;
24             }else
25             {
26                 c[i][j]=0;
27             }
28 
29             if (max_dis<=c[i][j])
30             {
31                 max_dis=c[i][j];
32                 index=i;
33             }
34         }
35 
36     }
37 
38     //output result
39     for (int i=index-max_dis;i<index;i++)
40     {
41         cout<<stra[i]<<' ';
42     }
43     cout<<endl;
44 
45     //free
46     for (int i=0;i<=len_a;i++)
47     {
48         delete[] c[i]; 
49     }
50     delete[] c;
51 
52     return max_dis;
53 }

 

posted @ 2016-01-29 14:28  summerxx  阅读(2635)  评论(0编辑  收藏  举报