LCS算法求最长公共子串

一、问题描述

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

注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中。
请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串。
例如:输入两个字符串BDCABA和ABCBDAB,字符串BCBA和BDAB都是是它们的最长公共子序列,则输出它们的长度4,并打印任意一个子序列。


二、最长公共子序列的结构

    最长公共子序列的结构有如下表示:

    设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, zk>,则:

  1. 若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的最长公共子序列;
  2. 若xm≠yn且zk≠xm ,则Z是Xm-1和Y的最长公共子序列;
  3. 若xm≠yn且zk≠yn ,则Z是X和Yn-1的最长公共子序列。

    其中Xm-1=<x1, x2, …, xm-1>,Yn-1=<y1, y2, …, yn-1>,Zk-1=<z1, z2, …, zk-1>。

三、子问题的递归结构

    由最长公共子序列问题的最优子结构性质可知,要找出X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的最长公共子序列,可按以下方式递归地进行:当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上xm(=yn)即可得X和Y的一个最长公共子序列。当xm≠yn时,必须解两个子问题,即找出Xm-1和Y的一个最长公共子序列及X和Yn-1的一个最长公共子序列。这两个公共子序列中较长者即为X和Y的一个最长公共子序列。

    由此递归结构容易看到最长公共子序列问题具有子问题重叠性质。例如,在计算X和Y的最长公共子序列时,可能要计算出X和Yn-1及Xm-1和Y的最长公共子序列。而这两个子问题都包含一个公共子问题,即计算Xm-1和Yn-1的最长公共子序列。

    与矩阵连乘积最优计算次序问题类似,我们来建立子问题的最优值的递归关系。用c[i,j]记录序列Xi和Yj的最长公共子序列的长度。其中Xi=<x1, x2, …, xi>,Yj=<y1, y2, …, yj>。当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故c[i,j]=0。其他情况下,由定理可建立递归关系如下:

四、算法实现

#include<stdio.h>
#include<iostream>
#include<string.h>

using namespace std;
enum Direction{Init=0,Up,LeftUp,Left};



void PrintLCS(int **LCS_Direct,char *pStr1,char *pStr2,int row,int col)
{
		if(pStr1 == NULL || pStr2 == NULL)  
        return;  
    size_t length1 = strlen(pStr1);  
    size_t length2 = strlen(pStr2);  
    
    if(length1 == 0 || length2 == 0 || !(row < length1+1 && col < length2+1))  
        return;
		if(LCS_Direct[row][col]==LeftUp)
		{
			  
				if(row>1&&col>1)
				{
					PrintLCS(LCS_Direct,pStr1,pStr2,row-1,col-1);
				}	
				cout<<pStr2[col-1];
		}  
  	else if(LCS_Direct[row][col]==Up)
  	{
				if(row>1)
				{
					PrintLCS(LCS_Direct,pStr1,pStr2,row-1,col);
				}	
		}
		else if(LCS_Direct[row][col]==Left)
  	{
				if(col>1)
				{
					PrintLCS(LCS_Direct,pStr1,pStr2,row,col-1);
				}	
		}
}


int LCS(char *pStr1,char *pStr2)
{
			if(!pStr1||!pStr2)
			{
				return 0;	
			}			
			size_t strLen1 = strlen(pStr1);
			size_t strLen2 = strlen(pStr2);
			if(strLen1==0||strLen2==0)
			{
				return 0;
			}
			//创建并初始化记录最大长度的矩阵 
			int i,j;
			int **LCS_Length;
			LCS_Length = (int**)(new int[strLen1+1]);
			for(i=0;i<strLen1+1;i++)
			{
					LCS_Length[i] = (int*)new	int[strLen2+1];
			}
			for(i=0;i<strLen1+1;i++)
			{
				for(j=0;j<strLen2+1;j++)
						{
							LCS_Length[i][j] = 0;	
						}
	   	}
			//创建并初始化记录方向的矩阵 
			int **LCS_Direct; 
			LCS_Direct = (int**)(new int[strLen1+1]);
			for(i=0;i<strLen1+1;i++)
			{
					LCS_Direct[i] =new int[strLen2+1];
			}
			for(i=0;i<strLen1+1;i++)
			{
				for(j=0;j<strLen2+1;j++)
						{
							LCS_Direct[i][j] = Init;	
						}
	   	}
			
			
			//构建最优解矩阵 
			for(i=0;i<strLen1;i++)
			{
				for(j=0;j<strLen2;j++)
				{
						if(pStr1[i]==pStr2[j])
						{
								LCS_Length[i+1][j+1]=LCS_Length[i][j]+1;
									LCS_Direct[i+1][j+1]=LeftUp;	
						} 
						else if(LCS_Length[i][j+1]>LCS_Length[i+1][j])
						{
								LCS_Length[i+1][j+1]=LCS_Length[i][j+1];
								LCS_Direct[i+1][j+1]=Up;	
						}
						else
						{
							  LCS_Length[i+1][j+1]=LCS_Length[i+1][j];
								LCS_Direct[i+1][j+1]=Left;
						}
				}	
			}		
			for(i=0;i<strLen1+1;i++)
			{
				for(j=0;j<strLen2+1;j++)
						{
							cout<<LCS_Length[i][j];	
						}
						cout<<endl;
	   	}
			PrintLCS(LCS_Direct,pStr1,pStr2,strLen1,strLen2);
			return LCS_Length[strLen1][strLen2];
}

int main(int argc,char *argv[])
{
		char *pStr1="ABCBDAB";
		char *pStr2="BDCABA";
		int len=LCS(pStr1,pStr2);
		cout<<"最大长度:"<<len<<endl;
	
		system("pause");
		return 0;	
}


原文链接: 动态规划解决最长公共串问题

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值