动态规划之最长公共子序列(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}的执行结果如下:

时间: 2024-12-10 20:46:38

动态规划之最长公共子序列(LCS)的相关文章

动态规划算法解最长公共子序列LCS问题

第一部分.什么是动态规划算法 ok,咱们先来了解下什么是动态规划算法. 动态规划一般也只能应用于有最优子结构的问题.最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似).简单地说,问题能够分解成子问题来解决. 动态规划算法分以下4个步骤: 描述最优解的结构 递归定义最优解的值 按自底向上的方式计算最优解的值   //此3步构成动态规划解的基础. 由计算出的结果构造一个最优解.   //此步如果只要求计算最优解的值时,可省略. 好,接下来,咱们

动态规划-最长公共子序列LCS

0 问题 给定两个字符串,求最长公共子序列LCS. 也就是说两个字符串中都有的部分,或者理解为,两个字符串同时都删除字符串中的某些字符,使得最终的两个字符串,相等,且是最长的. 1 分析 假设两个str1,str2字符串,已经知道了最长公共子序列长度为L 那么,当在str1和str2,两个的尾部,同时添加一个相同的字符,比如a,那么新的str1,和str2的最长公共子序列长度就是L+1 当str1后面添加一个字符,str2不添加,那么最长公共子序列长度为L 反之,str1不添加,str2添加,那

算法——动态规划篇——最长公共子序列

问题描述      最长公共子序列,英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列.       解决最长公共子序列,一种常用的办法,就是穷举法,组合出所有的情况,但是这样对于长序列的情况来说,是非常不实际.. 假设现在有两个序列,x[]={'A','B','C','B','D','A','B'};y[]={'B','D','C','A'

[2016-05-09][51nod][1006 最长公共子序列Lcs]

时间:2016-05-09 21:12:54 星期一 题目编号:[2016-05-09][51nod][1006 最长公共子序列Lcs] 题目大意:[2016-05-09][51nod][1006 最长公共子序列Lcs].md 分析:动态规划 dp[i][j] 表示字符串A以第i个位置 ,字符串B以第j个位置的最长公共子序列的长度 dp[i][j] = dp[i - 1][j - 1] + 1 if a[i] == a[j] else dp[i][j] == max(dp[i - 1][j] ,

动态规划解决最长公共子序列问题(转)

原文链接 动态规划法 经常会遇到复杂问题不能简单地分解成几个子问题,而会分解出一系列的子问题.简单地采用把大问题分解成子问题,并综合子问题的解导出大问题的解的方法,问题求解耗时会按问题规模呈幂级数增加. 解决思想: 为了节约重复求相同子问题的时间,引入一个数组,不管它们是否对最终解有用,把所有子问题的解存于该数组中,这就是动态规划法所采用的基本方法. [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后

动态规划解最长公共子序列问题(转)

 动态规划法 经常会遇到复杂问题不能简单地分解成几个子问题,而会分解出一系列的子问题.简单地采用把大问题分解成子问题,并综合子问题的解导出大问题的解的方法,问题求解耗时会按问题规模呈幂级数增加. 为了节约重复求相同子问题的时间,引入一个数组,不管它们是否对最终解有用,把所有子问题的解存于该数组中,这就是动态规划法所采用的基本方法. [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列

序列最的问题之最长公共子序列LCS

在程序设计竞赛中,我们时常会遇到序列求最值的问题.在讲今天的问题之前,先小小的说明一下,子序列与子串的问题. 子序列:在原序列中不一定连续: 子串:在原序列中必须连续. 接下来,就开始今天要讲的最长公共子序列LCS(Longest Common Subsequence).对于LCS这一类的问题,一般是相对于两个序列而言,str[]与ch[].先假设str的长度为n,ch的长度为m.假设str[]="ASBDAH",ch[]="SDAAH";其中"SDA&q

【算法导论之七】动态规划求解最长公共子序列

一.动态规划的概念 动态规划(Dynamic Programming)是通过组合子问题的解而解决整个问题的.分治算法是指将问题划分成一些独立的子问题,递归地求解各子问题,然后合并子问题的解而得到原始问题的解,与此不同,动态规划适用于子问题不是独立的情况,也就是各个子问题包含公共的子问题.在这种情况下,采用分治法会做许多不必要的工作,即重复地求解公共地子问题.动态规划算法对每个子问题只求解一次,将其结果保存在一张表中,从而避免每次遇到各个子问题时重新计算答案. 动态规划通常应用于最优化问题.此类问

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

我们之前提到过过动态规划的几个经典问题: 动态规划原理:http://blog.csdn.net/ii1245712564/article/details/45040037 钢条切割问题:http://blog.csdn.net/ii1245712564/article/details/44464689 矩阵链乘法问题:http://blog.csdn.net/ii1245712564/article/details/44464689 今天我们来看一下动态规划的另外一个经典问题:最长公共子序列(