【谈谈】动态规划——求最长公共子序列
首先,我们要搞清楚所谓最长公共子序列的概念。不然很容易把它和最长公共子串混淆,两者区别是:子序列只需要字符保持相对顺序,并不要求像公共字串那样组成字符还需连续。
问题:
给定两个字符串数组序列:
X[1...m] = {A, B, C, B, D, A, B}
Y[1...n] = {B, D, C, A, B, A}
求它们的最长公共子序列,我们可肉眼判断,这两个字符串数组序列的最长公共子序列长度为4.
“BDAB”
“BCAB”
“BCBA”
现在用代码解决这个问题,一般人比如说我最容易想到方法都是穷举法:
列出X的所有子序列,再在Y中找到和其匹配的最长子序列。
如果用穷举法解决,时间复杂度最多能达到O(n*2^m),也就是说,在一些特定场合比如校招面试,使用这种方法极易被pass。
再接来考虑递推
问题的核心就是找到X,Y的最长公共子序列,记为LCS(X,Y)。
如果xm = yn,则Ck = xm = yn 且 Ck-1是Xm-1和Yn-1的一个LCS
如果xm != yn 且 Ck != xm,则C是Xm-1和Y的一个LCS
如果xm != yn 且 Ck != yn,则C是X和Yn-1的一个LCS
public class 递归实现 {public static int Lcs(char x[],char y[],int i,int j) {if(i==0||j==0) {return 0;}else if(x[i]==y[j]) {return Lcs(x,y,i-1,j-1)+1;}else {return Max(Lcs(x,y,i-1,j),Lcs(x,y,i,j-1));}}private static int Max(int a,int b){if(a>b) {return a;}else {return b;}}
public static void main(String[] args) {//System.out.println((int)' ');String s1="ABCBDAB";char[] c1=new char[s1.length()+1];//带0字符的字符数组char[] t1=s1.toCharArray();c1[0]=(char)0;for(int i=1;i<t1.length;i++) {c1[i+1]=t1[i];}String s2="BDCABA";char[] c2=new char[s2.length()+1];//带0字符的字符数组char []t2=s2.toCharArray();c2[0]=(char)0;for(int i=1;i<t2.length;i++) {c2[i+1]=t2[i];}System.out.println(Lcs(c1,c2,c1.length-1,c2.length-1)) ;
}
}
但要是完全用递归求解,在整个二叉树的最有求解过程中,会有大量的重复调用。时间复杂度是指数级,并没有得到太大的优化。所以这里我们建议使用动态规划求解。
为了杜绝相关不必要重复步骤,我们选择用动态规划求解,通过备忘录或者说一张表来存放数据,避免重复的计算和调用,以空间换时间,同时本问题还符合动态规划的基本特征,求解最优子结构和重复子问题。
备忘录方法采用自顶向下方式,为每个解过的子问题建立了备忘录以备需要时查看,避免了相同子问题的重复求解
public class 备忘录法 {public static int Lcs(char x[],char y[],int i,int j,int bak[][]) {if(bak[i][j]!=-1) {return bak[i][j];}if(i==0||j==0) {return bak[i][j]=0;}else if(x[i]==y[j]) {return Lcs(x,y,i-1,j-1,bak)+1;}else {bak[i][j]=Max(Lcs(x,y,i-1,j,bak),Lcs(x,y,i,j-1,bak));}return bak[i][j];}private static int Max(int a,int b){if(a>b) {return a;}else {return b;}}
public static void main(String[] args) {//System.out.println((int)' ');String s1="ABCBDAB";char[] c1=new char[s1.length()+1];//带0字符的字符数组char[] t1=s1.toCharArray();c1[0]=(char)0;for(int i=1;i<t1.length;i++) {c1[i+1]=t1[i];}String s2="BDCABA";char[] c2=new char[s2.length()+1];//带0字符的字符数组char []t2=s2.toCharArray();c2[0]=(char)0;for(int i=1;i<t2.length;i++) {c2[i+1]=t2[i];}//初始化备忘录数组int [][]bak=new int[c1.length][c2.length];for(int i=0;i<c1.length;i++) {for(int j=0;j<c2.length;j++) {bak[i][j]=-1;}}System.out.println(Lcs(c1,c2,c1.length-1,c2.length-1,bak)) ;
}
}
备忘录法相比于递归以空间换时间,降低了时间复杂度,但占用内存会大大升高,并且它的时间复杂度相比于下面这种方法并不算太过优化。
动态规划—自底向上法:
采用自底向上方式,保存已求解的子问题,需要时取出,消除对某些子问题的重复求解.
import java.util.Scanner;public class 自底向上 {public static int Lcs(char x[],char y[],int i,int j,int bak[][]) {for(int ii=0;ii<=i;ii++) {for(int jj=0;jj<=j;jj++) {if(ii==0||jj==0) {bak[ii][jj]=0;}else if(x[ii]==y[jj]) {bak[ii][jj]= bak[ii-1][jj-1]+1;}else {bak[ii][jj]=Max(bak[ii-1][jj],bak[ii][jj-1]);}}}return bak[i][j];}private static int Max(int a,int b){if(a>b) {return a;}else {return b;}}
public static void main(String[] args) {Scanner s=new Scanner(System.in);//System.out.println((int)' ');String s1=s.nextLine();char[] c1=new char[s1.length()+1];//带0字符的字符数组char[] t1=s1.toCharArray();c1[0]=(char)0;for(int i=1;i<t1.length;i++) {c1[i+1]=t1[i];}String s2=s.nextLine();char[] c2=new char[s2.length()+1];//带0字符的字符数组char []t2=s2.toCharArray();c2[0]=(char)0;for(int i=1;i<t2.length;i++) {c2[i+1]=t2[i];}int [][]bak=new int[c1.length][c2.length];System.out.println(Lcs(c1,c2,c1.length-1,c2.length-1,bak)) ;
}
}
【谈谈】动态规划——求最长公共子序列相关推荐
- Java动态规划求最长公共子序列(LCS)
最长公共子序列(LCS) 定义:在序列X和序列Y中同时出现的元素,按照脚标从小到大排列的这样的序列. String x = "ABCBDABGGGTT"; ...
- Algorithm:C++/python语言实现之求旋转数组最小值、求零子数组、求最长公共子序列和最长公共子串、求LCS与字符串编辑距离
Algorithm:C++/python语言实现之求旋转数组最小值.求零子数组.求最长公共子序列和最长公共子串.求LCS与字符串编辑距离 目录 一.求旋转数组最小值 1.分析问题 2.解决思路 二.求 ...
- 实验二 动态规划算法 最长公共子序列问题
基本题一:最长公共子序列问题 一.实验目的与要求 1.熟悉最长公共子序列问题的算法: 2.初步掌握动态规划算法: 二.实验题 若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,z ...
- 动态规划解决最长公共子序列
动态规划解决最长公共子序列 问题描述 给定两个序列,例如 X = "ABCBDAB".Y = "BDCABA",求它们的最长公共子序列的长度. 递归关系 c[i ...
- 求最长公共子序列长度
求两个字符串的公共子序列 1.求最长公共子序列(子序列可以不连续) 这是一道动态规划题,设二维数组dp[i][j],dp[i][j]表示a串前i个字符(包括第i个)与b串前j个字符(包括第j个)所有的 ...
- 动态规划解最长公共子序列(LCS)(附详细填表过程)
目录 相关概念 子序列形式化定义: 公共子序列定义: 最长公共子序列(以下简称LCS): 方法 蛮力法求解最长公共子序列: 动态规划求解最长公共子序列: 分析规律: 做法: 伪代码: 下面演示下c数组 ...
- 动态规划篇——最长公共子序列(c++)
引言:最长公共子序列属于动态规划的基础篇,由字符串的最长公共最序列可以引出很多的问题. 最长子序列详细讲解以及练习题目 需要详细讲解教程的可以观看上面链接的文章,以下是自己做的简单的概括. 一.何为最 ...
- 动态规划之——最长公共子序列(nyoj36)
问题描述: 最长公共子序列 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列. tip:最长公共子序 ...
- 2192-Zipper 求最长公共子序列的解题报告
主要的思考方向就是求dp里面的最长公共子序列.至于字符串本身的判别并不是重点. 根据网上poj的分类,这个题是dp求最长公共子序列,其实用暴力的方法也能通过.暴力的方法比较简单就不多说了.主要讲讲dp ...
最新文章
- UIPickerView和UIDataPicker
- Visual Studio将原生支持WSL 2
- 免费算力提供!这个含YOLOv3算法讲解的深度学习课程来了
- 数学知识点回顾(三)
- 现代软件工程个人作业进度
- Nginx 的 server_names_hash_bucket_size 问题
- 新手进阶:巧用 macOS 帮助菜单?
- 如何为自己的在线办公软件 ONLYOFFICE Docs 服务器的字体库添加字体
- 航模入门经典教材:航空模型教材
- 十五届恩智浦智能车-四十天做四轮-调车日记
- Win7环境下VS2015安装+CUDA 10.0安装配置教程以及安装环境时遇到的一些问题
- python模拟别人说话的声音_现在你可以通过深度学习用别人的声音来说话了
- matlab制作科学计算器,基于MATLAB科学计算器
- 首次使用计算机 鼠标没反应,电脑鼠标没反应是怎么回事
- 积极心理学第十九课 如何让爱情天长地久
- 大连交通大学IPTV使用方法
- 基于ESP8266的STM32物联网开发板
- CFileDialog 异常问题
- backtrack5 初步配置
- c语言列车信息管理系统,C语言火车票信息管理系统.doc