当前位置:编程学习 > C/C++ >>

最长公共子字符串

描述:
求两个输入序列的最长的公共子字符串的长度。子字符串中的所有字符在源字符串中必须相邻。
 
如字符串:21232523311324和字符串312123223445,他们的最长公共子字符串为21232,长度为5。
 
输入格式:
两行,第一行为第一个字符串X,第二行为第二个字符串Y,字符串不含空格并以回车标示结束。X和Y的串长都不超过100000。
输出格式:
两行,第一行为最长的公共子字符串的长度,第二行输出一个最长的公共子字符串。
 
说明:
(1)若最长的公共子字符串有多个,请输出在源字符串X中靠左的那个。
(2)若最长公共子字符串的长度为0,请输出空串(一个回车符)。
 
如输入:
21232523311324
152341231
由于523和123都是最长的公共子字符串,但123在源串X中更靠左,因此输出:
3
123
 
分析:
最长公共子字符串必须是连续的。如果我们使用递归的方法解决的话,对于每一对字符就需要判断前面的是否已构成字串,这就会使子问题出现重复计算的问题。对于重复子问题,还是要使用动态规划的思想。
 
假设需要求的字符串为 str1 , str2 .函数 f(m,n) 求分别以str1[m] , str2[n] 结尾的公共字符串长度。
这有一下递推公式:
 
f(m,n)=0        str1[m] != str2[n] ;
f(m,n)=f(m-1,n-1) + 1      str[m]==str2[n];
 
别忘了递推的特殊边界:
f(0,n)=0;
f(m,0)=0;
 
 
 
 
代码如下:
 
#include<iostream>  
#include<string.h>  
using namespace std;  
  
int c[10000][10000];  
char str1[10000];  
char str2[10000];  
  
  
void func(int m,int n){  
      if((m<0)||(n<0)) return ;  
  
       for(int i=0;i<m;i++)  
         for(int j=0;j<n;j++) c[i][j]=0;  
  
      int besti=0,bestj=0;  
      int count=0;  
  
      for(int i=0;i<m;i++)  
          for(int j=0;j<n;j++)  
              if(str1[i]==str2[j]) {  
                  if((i==0)||(j==0)) c[i][j]=1;   //增加判断是否为第一个,第一个不能再向下  
                  else  c[i][j]=c[i-1][j-1] + 1 ;  
              }  
              else c[i][j]=0;  
  
/* 
     for(int i=0;i<m;i++){ 
         for(int j=0;j<n;j++) 
             cout<<c[i][j]<<' '; 
         cout<<endl; 
     } 

*/  
  
     for(int i=0;i<m;i++)  
         for(int j=0;j<n;j++)  
             if(c[i][j]>count) { count=c[i][j]; besti=i; bestj=j; }   //查找最长子字符串  
  
     cout<<count<<endl;  
     if(count==0) cout<<endl;  //公共子字符串长度为1,输出空行  
     else  
        for(int i=besti-count+1;i<=besti;i++) cout<<str1[i];   //否则输出靠X左边(如果多个)子字符串  
  
  
}  
  
  
int main() {  
    int m=0;  
    int n=0;  
    cin>>str1;  
    cin>>str2;  
    m=strlen(str1);  
    n=strlen(str2);  
    func(m,n);  
    return 0;  
}  

 


补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,