动态规划之最长公共子序列问题

以算法导论为指导书慢慢看算法的第二个算法,

动态规划算法解决最长公共子序列

 

假如我们有两个字符串:X=[0,1,2....n]  Y=[0,1,2...m]。我们定义L(i, j)为X[0...i]与Y[0...j]之间的最长公共子序列的长度。通过动态规划思想(复杂问题的最优解是子问题的最优解和子问题的重叠性质决定的)。我们考虑这样两种情况:

 

(1)  当X[i]=Y[j]时, L(i, j)=L(i-1, j-1)+1 。证明很简单。

(2)  当X[i]!=Y[j]时, 说明此事X[0...i]和Y[0...j]的最长公共子序列中绝对不可能同时含有X[i]和Y[j]。那么公共子序列可能以X[i]结尾,可能以Y[j]结尾,可以末尾都不含有X[i]或Y[j]。因此

                               L(i, j)= MAX{L(i-1 , j), L(i, j-1)}

代码如下,有注释,请细看。

package blut.Algorithms.dongtaiguihua;

/**
 * 最长公共子串LCS
 * @author heartraid
 */
public class LCS {

	/**字符串X的字符数组*/
	private char[] charArrayX=null;
	/**字符串Y的字符数组*/
	private char[] charArrayY=null;

	public LCS(String sa,String sb){
		charArrayX=new char[sa.length()+1];
		System.arraycopy(sa.toCharArray(),0,charArrayX,1,sa.length());
		charArrayY=new char[sb.length()+1];
		System.arraycopy(sb.toCharArray(),0,charArrayY,1,sb.length());
	}
	
	/**
	 * 得到最长公共子序列的长度
	 */
	public void getLCS(){
		
		int[][] length=new int[charArrayX.length+1][charArrayY.length+1];
		
		for(int m=1;m<charArrayX.length;m++)
			for(int n=1;n<charArrayY.length;n++){
				if(charArrayX[m]==charArrayY[n]){
					length[m][n]=length[m-1][n-1]+1;
				}
				else
					length[m][n]=max(length[m-1][n],length[m][n-1]);					
			}
		//打印最长公共子序列
		String lcstr="";
		int x=charArrayX.length-1;
		int y=charArrayY.length-1;
		while(x>=1 && y>=1){
			if(charArrayX[x]==charArrayY[y]){
				lcstr=charArrayX[x]+lcstr;
				x--;
				y--;
			}else{
				if(length[x-1][y]<=length[x][y-1])
					y--;
				else
					x--;	
			}
		}
		System.out.println("最长公共子序列为:"+lcstr+" [length="+lcstr.length()+"]");
	}
	/**
	 * 取最大值
	 */
	private int max(int m,int n){
		return m>n?m:n;
	}	
	
	/**
	 * 测试
	 */
	public static void main(String[] args) {
		LCS lcs=new LCS("abcdf","abcd");
		lcs.getLCS();
	}

}


结果是:

最长公共子序列为:abcd [length=4]



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值