• 算法设计与分析——最长公共子序列(LCS)备忘录法和动态规划实现


    问题描述

           首先我们需要理解:最长公共子序列(longest common sequence)和最长公共子串(longest common substring)不是一回事儿。什么是子序列呢?即一个给定的序列的子序列,就是将给定序列中零个或多个元素去掉之后得到的结果。什么是子串呢?给定串中任意个连续的字符组成的子序列称为该串的子串。详见下图:
                  

           也就是说,最长公共子序列不一定连续!

           而最长公共子序列问题就是:求解两个序列的最长公共子序列的长度。这里采用动态规划法和备忘录法求解。

    两种方法对比:

    备忘录方法

    • 备忘录方法要用递归实现
    • 递归是自顶向下的解决问题的:即从目标开始,将问题划分,对子问题求解,直到边界
    • 递归前对备忘录进行查询,当前备忘录未被填写时,则进行递归,否则直接返回备忘录的内容(核心,提高算法效率)
    • 当整个问题的求解过程中有大量子问题无需求解时,备忘录更省时
    • 一般要对备忘录进行初始化,为了之后快速判断是否有已经填写过备忘录

    动态规划法

    • 通过循环实现
    • 递推式是自下而上解决问题的:即从边界开始,逐步对问题求解,直到抵达目标
    • 当整个问题的求解过程中全部都要进行计算时,则应该使用递推式

    递归公式

                  

    核心代码

    //	动态规划
    	 public static void f1(char arr1[],char arr2[],int n,int m) {
    	        for(int i=1;i<=n;i++) {
    	            for(int j=1;j<=m;j++) {
    	                if(arr1[i-1]==arr2[j-1]) {
    	                    dp[i][j]=dp[i-1][j-1]+1;
    	                }else {
    	                    dp[i][j]=Math.max(dp[i-1][j], dp[i][j-1]);
    	                }
    	            }
    	        }
    	        System.out.println(dp[n][m]);
    	    }
    	 //	备忘录
    	public static int f2(char arr1[],char arr2[],int n,int m) {
    		if(n==0||m==0) {
    			return 0;
    		}else if(arr1[n-1]==arr2[m-1]) {
    			dp[n][m]=f2(arr1,arr2,n-1,m-1)+1;
    		}else {
    		
    			 dp[n][m]=Math.max(f2(arr1,arr2,n-1,m),f2(arr1,arr2,n,m-1));}
    		return dp[n][m];
    	}
    

    完整代码在:https://gitee.com/KSRsusu/arithmetic/tree/master/src

    运行示例

           从短的开始逐个与长的开始匹配,解析与结果如图:
                  

    参考博客

    https://blog.csdn.net/hrn1216/article/details/51534607

  • 相关阅读:
    el-table——可编辑拖拽转换csv格式的表格
    【C#进阶系列】25 线程基础
    【C#进阶系列】24 运行时序列化
    【C#进阶系列】23 程序集加载和反射
    【C#进阶系列】22 CLR寄宿和AppDomain
    【C#进阶系列】21 托管堆和垃圾回收
    【C#进阶系列】20 异常和状态管理
    【C#进阶系列】19 可空值类型
    【C#进阶系列】18 特性Attribute
    【C#进阶系列】17 委托
  • 原文地址:https://www.cnblogs.com/Monster-su/p/14579852.html
Copyright © 2020-2023  润新知