动态规划----最长公共子序列(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的最长公共子序列(子序列不要求是连续的). ...
随机推荐
- windows10中微软小娜cortana如何彻底卸载删除?
windows10中的Cortana可以通过语音干很多事情,但是对于我们来说用处不大,而且开机十分占用内存,下面教大家如何彻底的卸载并删除: 首先下载卸载Cortana的软件,下载链接:http:// ...
- thinkphp5简单使用redis缓存
<?php namespace app\index\controller; use think\Controller; use think\Cache\Driver\Redis; class I ...
- rpm和yum软件管理
rpm简介 数据库管理工具,通过读取数据库,判断软件是否安装,如已安装可读取出来所有文件的所在位置等,并可以实现删除这些文件. rpm:RPM is Redhat Package Manager(递归 ...
- postgresql 53300错误
1.查看当前库的最大连接数 show max_connections; 2.查看当前数据库的活动连接数 select datname,application_name,pid,state from p ...
- codeforces / project Euler 泛做
目录 PE 15 PE 76 PE 90 PE 577 PE 97 PE 364(坑) 待做 发现这个题库,很有意思,趁着还没有学习微积分,看不了书,赶快从头开始刷,所以都是一些简单的题目,即时简单, ...
- 神器PHPStorm个人最常用快捷键
PHPStorm是目前PHP开发者最常用的IDE之一,善用快捷键可以极大地提升效率,网上有很多盘点,多而全,但很多要么不实用,要么操作不方便,下面盘点一下个人平时最常用的,亲测有效. CTRL+N 查 ...
- main方法启动spring
main方式读取spring配置.main方法启动spring/ 有时候只想写一下简单的测试用一下. 新建一个maven项目 依赖pom <?xml version="1.0" ...
- notes for lxf(五)
类和实例的绑定方法和属性 实例绑定 obj.func = func obj.func(obj, &argv) obj.func = MethodType(func, obj) 第一个参数是方 ...
- Luogu P3381 (模板题) 最小费用最大流
<题目链接> 题目大意: 给定一张图,给定条边的容量和单位流量费用,并且给定源点和汇点.问你从源点到汇点的最带流和在流量最大的情况下的最小费用. 解题分析: 最小费用最大流果题. 下面的是 ...
- 光纤网卡与HBA卡区别
1.简介 光纤网卡 ,指的是光纤以太网适配器,简称光纤网卡,学名Fiber Ethernet Adapter.传输输的是以太网通信协议,一般通过光纤线缆与光纤以太网交换机连接.按传输速率可以分为100 ...