码迷,mamicode.com
首页 > 其他好文 > 详细

动态规划之最长公共子序列(LCS)

时间:2015-05-19 22:47:02      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:动态规划   lcs   最长公共子序列   算法   

tips : 本文内容是参考了很多著名博客和自己的思考得出的,如有不当欢迎拍砖技术分享


先简单说一下动态规划

通俗地说:动态规划就是将一个可以划分为子问题的问题进行递归求解,不过动态规划将大量的中间结果保存起来,

管它们是否会用得到,从而在后面的递归求解过程中可以快速求解。由此可以看得出来动态规划是一个以牺牲空间

为代价换取时间的算法。

对于最长公共子序列的题目不用多说,现在来分析一下LCS的动态规划解决思路:

一、首先先观察问题是否符合动态规划最明显的两个特征:最优子结构和重叠子问题

方便起见,以x = {a,d,f,s,d}序列和y = {a,s,d,f}序列为例进行说明,z序列为x序列和y序列的最长公共子序列。

1. 最优子结构

    首先观察x序列和y序列的第一项可知x1=y1,因此a肯定是z中的第一项。接下来,由于x2!=y2,因此对于z序列中

z2-zn存在两种情况:要么z2-zn存在于[{d,f,s,d},{d,f}]中或者存在于[{f,s,d},{s,d,f}]中。但是不管最终是哪

种情况,都避免不了要计算[{f,s,d},{d,f}]这种情况。由此可得该问题满足最优子结构的特点。

2.重叠子问题

    前面说到,求x序列和y序列的最长公共子序列有可能会求x-1和y的子序列或者求x和y-1的子序列,而对这两种情

况进行递归求解的时候,都会涉及到求x-1和y-1的情况,也就是说存在重叠子问题的特点。

二、建立状态转移方程

    用mix[a][b]来记录xa和yb的最长子序列,当x[a]=y[b]时:mix[a][b] = mix[a-1][b-1] + 1;当x[a]!=y[b]

时:mix[a][b]=MAX{mix[a-1][b],mix[a][b-1]}。即:

mix[a][b] = mix[a-1][b-1] + 1 x[a] = y[b]

mix[a][b] =MAX{mix[a-1][b],mix[a][b-1]} x[a] !=y[b]


由以上分析不难得出代码如下:


import java.util.Scanner;

public class Main {

	static String[] str1;
	static String[] str2;
	// 使用矩阵记录数据
	static int[][] mix;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);

		str1 = sc.nextLine().trim().split(" ");
		str2 = sc.nextLine().trim().split(" ");
		sc.close();
		// 初始化矩阵
		mix = new int[str2.length + 1][str1.length + 1];
		// DP填充矩阵
		lcs();
		// 打印矩阵
		printMix();
		
		System.out.println("最长公共子序列的长度:" + mix[str2.length][str1.length]);
	}

	/**
	 * DP填充矩阵
	 */
	private static void lcs() {
		for (int a = 1; a < str2.length + 1; a++) {
			for (int b = 1; b < str1.length + 1; b++) {
				if (str2[a - 1].equals(str1[b - 1])) {
					mix[a][b] = mix[a - 1][b - 1] + 1;
				} else {
					mix[a][b] = Math.max(mix[a - 1][b], mix[a][b - 1]);
				}
			}
		}
	}

	/**
	 * 打印矩阵数据
	 */
	private static void printMix() {
		System.out.println("打印矩阵数据:");
		System.out.print("  ");
		for (String s : str1) {
			System.out.print(s + " ");
		}
		System.out.println();
		for (int a = 1; a < str2.length + 1; a++) {
			System.out.print(str2[a - 1] + " ");
			for (int b = 1; b < str1.length + 1; b++) {
				System.out.print(mix[a][b] + " ");
			}
			System.out.println();
		}
	}

}


对于测试数据x = {a,d,f,s,d}序列和y = {a,s,d,f}的执行结果如下:


技术分享


动态规划之最长公共子序列(LCS)

标签:动态规划   lcs   最长公共子序列   算法   

原文地址:http://blog.csdn.net/u011333588/article/details/45849263

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!