动态规划----最长公共子序列(LCS)问题
题目:
求解两个字符串的最长公共子序列。如 AB34C 和 A1BC2 则最长公共子序列为 ABC。
思路分析:可以用dfs深搜,这里使用到了前面没有见到过的双重循环递归。也可以使用动态规划,在建表的时候一定要注意初始化以及在发现规律的时候一定要想怎么利用前面已经算过的结果来得到现在的结果,或者利用其他的一些规律来发现能够解题的规律。
图中单元格需要填上相应的数字(这个数字就是dp[i][j]的定义,记录的LCS的长度值)。可以发现规律,简单来说:如果横竖(i,j)对应的两个元素相等,该格子的值 = c[i-1,j-1] + 1。如果不等,取c[i-1,j] 和 c[i,j-1]的最大值。
当得到完整的DP表之后,我们可以通过倒推来得到相应的子序列,有时S1和S2的LCS并不是只有1个,本题并不是着重说要输出两个序列的所有LCS,只是要输出其中一个LCS。
代码:
import java.util.ArrayList;
public class LCS {
public static void main(String[] args) {
ArrayList ans = dfs("AB34C", "A1BC2");
System.out.println(ans); // 输出 [A, B, C]
System.out.println(dfs("3563243", "513141")); // 输出 [5, 3, 4]
System.out.println(solution("3069248", "513164318")); // 输出 [3, 6, 4, 8]
System.out.println(solution("123", "456")); // 输出为空
}
// 双重循环递归
static ArrayList<Character> dfs(String s1, String s2) {
int len1 = s1.length();
int len2 = s2.length();
ArrayList<Character> ans = new ArrayList<>();
for (int i = 0; i < len1; i++) {
// 求以i字符开头的公共子序列
ArrayList<Character> list = new ArrayList<>();
// 和s2的每个字符比较
for (int j = 0; j < len2; j++) {
if (s1.charAt(i) == s2.charAt(j)) {// 如果相同
list.add(s1.charAt(i));
list.addAll(dfs(s1.substring(i + 1), s2.substring(j + 1)));
break;
}
}
if (list.size() > ans.size()) {
ans = list;
}
}
return ans;
}
/**
* 生成动规表
*/
static String solution(String s1, String s2) {
int len1 = s1.length();
int len2 = s2.length();
int[][] dp = new int[len1 + 1][len2 + 1]; // 动规数组
int flag = 0;
// 初始化第一列
// O(M)
for (int i = 1; i <= len1; i++) {
if (flag == 1) {
dp[i][1] = 1;
} else if (s1.charAt(i - 1) == s2.charAt(0)) {
dp[i][1] = 1;
flag = 1;
} else {
dp[i][1] = 0;
}
}
flag = 0;
// 初始化第一行
// O(N)
for (int j = 1; j <= len2; j++) {
if (flag == 1) {
dp[1][j] = 1;
} else if (s2.charAt(j - 1) == s1.charAt(0)) {
dp[1][j] = 1;
flag = 1;
} else {
dp[1][j] = 0;
}
}
// O(M*N)
for (int i = 2; i <= len1; i++) { // M
for (int j = 2; j <= len2; j++) { // N
int maxOfLeftAndUp = Math.max(dp[i - 1][j], dp[i][j - 1]);
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
// dp[i][j] = Math.max(maxOfLeftAndUp, dp[i - 1][j - 1] + 1);
dp[i][j] = dp[i - 1][j - 1] + 1;// 这样也是对的……
} else {
dp[i][j] = maxOfLeftAndUp;
}
}
}
return parseDp(dp, s1, s2);
}
/**
* 解析动态规划表,得到最长公共子序列
*/
private static String parseDp(int[][] dp, String s1, String s2) {
int M = s1.length();
int N = s2.length();
StringBuilder sb = new StringBuilder();
while (M > 0 && N > 0) {
// 比左和上大,一定是当前位置的字符相等
if (dp[M][N] > Math.max(dp[M - 1][N], dp[M][N - 1])) {
sb.insert(0, s1.charAt(M - 1));
M--;
N--;
} else { // 一定选择的是左边和上边的大者
if (dp[M - 1][N] > dp[M][N - 1]) {
M--; // 往上移
} else {
N--; // 往左移
}
}
}
return sb.toString();
}
}
动态规划----最长公共子序列(LCS)问题的更多相关文章
- 动态规划 最长公共子序列 LCS,最长单独递增子序列,最长公共子串
LCS:给出两个序列S1和S2,求出的这两个序列的最大公共部分S3就是就是S1和S2的最长公共子序列了.公共部分 必须是以相同的顺序出现,但是不必要是连续的. 选出最长公共子序列.对于长度为n的序列, ...
- 动态规划——最长公共子序列LCS及模板
摘自 https://www.cnblogs.com/hapjin/p/5572483.html 这位大佬写的对理解DP也很有帮助,我就直接摘抄过来了,代码部分来自我做过的题 一,问题描述 给定两个字 ...
- 动态规划之最长公共子序列LCS(Longest Common Subsequence)
一.问题描述 由于最长公共子序列LCS是一个比较经典的问题,主要是采用动态规划(DP)算法去实现,理论方面的讲述也非常详尽,本文重点是程序的实现部分,所以理论方面的解释主要看这篇博客:http://b ...
- 《算法导论》读书笔记之动态规划—最长公共子序列 & 最长公共子串(LCS)
From:http://my.oschina.net/leejun2005/blog/117167 1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要 ...
- 编程算法 - 最长公共子序列(LCS) 代码(C)
最长公共子序列(LCS) 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 给定两个字符串s,t, 求出这两个字符串最长的公共子序列的长度. 字符 ...
- C++版 - Lintcode 77-Longest Common Subsequence最长公共子序列(LCS) - 题解
版权声明:本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C++版 - L ...
- 1006 最长公共子序列Lcs
1006 最长公共子序列Lcs 基准时间限制:1 秒 空间限制:131072 KB 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdks ...
- POJ 1458 Common Subsequence(最长公共子序列LCS)
POJ1458 Common Subsequence(最长公共子序列LCS) http://poj.org/problem?id=1458 题意: 给你两个字符串, 要你求出两个字符串的最长公共子序列 ...
- 51Nod 1006:最长公共子序列Lcs(打印LCS)
1006 最长公共子序列Lcs 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...
随机推荐
- java程序设计第二次作业
- 差分线Layout的两个误区
误区一:认为差分线可以相互之间耦合,所以可以相互之间提供回流路径,不需要地作为回流路径: 其实在信号回流分析上,差分走线和普通的单端走线的机理是一致的,即高频信号总是沿着电感最小的回路进行回流.最大的 ...
- Django—常用功能
索引 一.静态文件 二.中间件 三.Admin站点 3.1 列表页选项 3.2 编辑页选项 3.3 重写模板 四.上传图片 4.1 在管理页面admin中上传图片 4.2 自定义form表单中上传图片 ...
- 2018-2019-2 20165314《网络对抗技术》Exp1 PC平台逆向破解
实践目的 本次实践的对象是一个名为pwn1的linux可执行文件.该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. 该程序同时包含另一个代码片段,getShel ...
- 时分秒计时器 js
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 关于 gitignore
前言 通过在一个 gitignore 文件里面添加相关的规则,我们可以让 git 在追踪文件时忽略一些特定的文件(gitignore 文件泛指所有存放忽略规则的文件,不仅仅是指 .gitignore ...
- winxp改AHCI不再蓝屏,不用改注册表,所有PC机通用
要用win8的pe 在通常的情况下,硬盘在BIOS中默认为原生IDE模式以获得最好的兼容性.对配件要求较高的W7,W8系统中,而通过开启硬盘AHCI模式,可以在一定程度上提升硬盘的性能表现.如果在ID ...
- docker 安装 hbase安装 java连接hbase (mac环境)
docker 安装 https://hub.docker.com/editions/community/docker-ce-desktop-mac 下载地址 下载完之后,安装app一样安装就好 安装完 ...
- SpringBoot的自动配置原理
一.入口 上篇注解@SpringBootApplication简单分析,说到了@SpringBootApplication注解的内部结构, 其中@EnableAutoConfiguration利用En ...
- 【spring】-- springboot配置全局异常处理器
一.为什么要使用全局异常处理器? 什么是全局异常处理器? 就是把错误异常统一处理的方法. 应用场景: 1.当你使用jsr303参数校验器,如果参数校验不通过会抛异常,而且无法使用try-catch语句 ...