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


    最长公共子序列(LCS)问题

    下面通过一个具体的例子来学习动态规划方法 —— 最长公共子序列问题。

    最长公共子串(Longest Common Substring)最长公共子序列(Longest Common Subsequence)的区别: 子串要求在原字符串中是连续的,而子序列则只需保持相对顺序,并不要求连续。

    问题描述:给定两个序列:X[1...m]Y[1...n],求在两个序列中同时出现的最长子序列的长度。

    假设 X 和 Y 的序列如下:

          X[1...m] = {A, B, C, B, D, A, B}  

          Y[1...n] = {B, D, C, A, B, A}  

    可以看出,X 和 Y 的最长公共子序列有 “BDAB”、“BCAB”、“BCBA”,即长度为4。

    1) 穷举法

    可能很多人会想到用穷举法来解决这个问题,即求出 X 中所有子序列,看 Y 中是否存在该子序列。

      X 有多少子序列 —— 2m 个

      检查一个子序列是否在 Y 中 —— θ(n)

    所以穷举法在最坏情况下的时间复杂度是 θ(n2m),也就是说花费的时间是指数级的,这简直太慢了。

    2) 动态规划

    首先,我们来看看 LCS 问题是否具有动态规划问题的两个特性。

    ① 最优子结构

    设 C[i,j] = |LCS(x[1...i],y[1...j])|,即C[i,j]表示序列X[1...i]Y[1...j]的最长公共子序列的长度,则 C[m,n] = |LCS(x,y)|就是问题的解。

    递归推导式:

    根据上面的递归推导式,可以写出求LCS长度的递归伪代码:

    LCS(x,y,i,j)
    	if x[i] = y[j]
    		then C[i,j] ← LCS(x,y,i-1,j-1)+1
    		else C[i,j] ← max{LCS(x,y,i-1,j),LCS(x,y,i,j-1)}
    	return C[i,j]

    动态规划就是要解决这个问题,通过用一个表来保存子问题的结果,避免重复的计算,以空间换时间。前面我们已经证明,最长公共子序列问题具有动态规划所要求的两个特性,所以 LCS 问题可以用动态规划来求解。

    下面是用动态规划(打表)解决LCS问题:

    private static int lcs(char[] x, char[] y, int m, int n) {
    		if (m == 0 || n == 0) {
    			return 0;
    		}
    		int[][] c = new int[m + 1][n + 1];
    		for (int i = 1; i < m + 1; i++) {
    			for (int j = 1; j < n + 1; j++) {
    				if (x[i - 1] == y[j - 1]) {
    					c[i][j] = c[i - 1][j - 1] + 1;
    				} else {
    					c[i][j] = Math.max(c[i][j - 1], c[i - 1][j]);
    				}
    			}
    		}
    		return c[m][n];
    	}
    

      

  • 相关阅读:
    好书推介《实战机器学*》
    Web技术图书名单
    大数据技术书,看看有没有感兴趣的
    博客园设置自定义皮肤,添加自定义小模块悬浮天气组件,github图标链接等
    Final Cut Pro 视频剪辑学习记录,快捷操作等
    css 利用 clip-path 裁剪多边形,三角形,梯形,六边形等
    有呀,有呀,设计!有呀,有呀,组件!
    github README添加badge标识,多彩的tag标签
    vue timeline 开箱即用的时间轴组件,日志更新时间轴组件
    那些需要收藏的网站网址
  • 原文地址:https://www.cnblogs.com/sunTin/p/6672861.html
Copyright © 2020-2023  润新知