动态规划----最长公共子序列(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的最长公共子序列(子序列不要求是连续的). ...
随机推荐
- nginx实现Ipv6地址解析
nginx实现Ipv6地址解析 1.nginx实现Ipv6地址解析 [root@ip-10-109-1-47 conf]# cat nginx.conf worker_processes 2; eve ...
- Celery初识及简单实例
Celery是一个“自带电池”的任务队列.易于使用,可以轻易入门,它遵照最佳实践设计,使产品可以扩展,或与其他语言集成,并且它自带了在生产环境中运行这样一个系统所需的工具和支持.本文介绍基础部分: 选 ...
- sql-我写的或者其他人写的
1.更新数据,补上分工 UPDATE smartoperator RIGHT JOIN smartoperation ON smartoperation.ID=smartoperator.Operat ...
- 小程序-组件component和模版template的选择和使用
小程序提供了组件component和模版template那什么时候 选择哪一个使用呢?我总结了一下 template主要是模版,对于重复的展示型模块进行展示,其中调用的方法或者数据data都是需要引用 ...
- Codeforces 677E Vanya and Balloons
Vanya and Balloons 枚举中心去更新答案, 数字过大用log去比较, 斜着的旋转一下坐标, 然后我旋出来好多bug.... #include<bits/stdc++.h> ...
- 闲谈REST API
REST 表述性状态传递(英文:Representational State Transfer,简称REST). 资源: 资源由URI(统一资源定位符)的来指定. 通过资源的表现形式来操作资源 对资源 ...
- Android进阶:二、从源码角度看透 HandlerThread 和 IntentService 本质
上篇文章我们讲日志的存储策略的时候用到了HandlerThread,它适合处理"多而小的任务"的耗时任务的时候,避免产生太多线程影响性能,那这个HandlerThread的原理到底 ...
- jdk1.8安装
jdk1.8:链接: https://pan.baidu.com/s/1Orv7Rjz0jkprcdoRSFWiPw 提取码: rn73 设置jdk和jre文件位置 配置环境变量: 系统变量中jdk ...
- linux 使用技巧 screen 管理你的远程桌面的会话创建和使用
下面介绍 screen 使用的技巧教你管理远程会话 你是不是经常需要 SSH 或者 telent 远程登录到 Linux 服务器?你是不是经常为一些长时间运行的任务而头疼,比如系统备份. ftp 传 ...
- Mac安装sqlite3
1,下载最新版本的 Mac OS X 会预安装 SQLite,但是如果没有可用的安装,只需按照如下步骤进行: 去安装最新的3.8.6版本,和linux的sqlite3安装版本是同一个. 软件地址为:h ...