题目:

  求解两个字符串的最长公共子序列。如 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)问题的更多相关文章

  1. 动态规划 最长公共子序列 LCS,最长单独递增子序列,最长公共子串

    LCS:给出两个序列S1和S2,求出的这两个序列的最大公共部分S3就是就是S1和S2的最长公共子序列了.公共部分 必须是以相同的顺序出现,但是不必要是连续的. 选出最长公共子序列.对于长度为n的序列, ...

  2. 动态规划——最长公共子序列LCS及模板

    摘自 https://www.cnblogs.com/hapjin/p/5572483.html 这位大佬写的对理解DP也很有帮助,我就直接摘抄过来了,代码部分来自我做过的题 一,问题描述 给定两个字 ...

  3. 动态规划之最长公共子序列LCS(Longest Common Subsequence)

    一.问题描述 由于最长公共子序列LCS是一个比较经典的问题,主要是采用动态规划(DP)算法去实现,理论方面的讲述也非常详尽,本文重点是程序的实现部分,所以理论方面的解释主要看这篇博客:http://b ...

  4. 《算法导论》读书笔记之动态规划—最长公共子序列 & 最长公共子串(LCS)

    From:http://my.oschina.net/leejun2005/blog/117167 1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要 ...

  5. 编程算法 - 最长公共子序列(LCS) 代码(C)

    最长公共子序列(LCS) 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 给定两个字符串s,t, 求出这两个字符串最长的公共子序列的长度. 字符 ...

  6. C++版 - Lintcode 77-Longest Common Subsequence最长公共子序列(LCS) - 题解

    版权声明:本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C++版 - L ...

  7. 1006 最长公共子序列Lcs

    1006 最长公共子序列Lcs 基准时间限制:1 秒 空间限制:131072 KB 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdks ...

  8. POJ 1458 Common Subsequence(最长公共子序列LCS)

    POJ1458 Common Subsequence(最长公共子序列LCS) http://poj.org/problem?id=1458 题意: 给你两个字符串, 要你求出两个字符串的最长公共子序列 ...

  9. 51Nod 1006:最长公共子序列Lcs(打印LCS)

    1006 最长公共子序列Lcs  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...

随机推荐

  1. 算法工程师<深度学习基础>

    <深度学习基础> 卷积神经网络,循环神经网络,LSTM与GRU,梯度消失与梯度爆炸,激活函数,防止过拟合的方法,dropout,batch normalization,各类经典的网络结构, ...

  2. python3 切片

    一.切片的目的:获取多个元素 能够进行切片的对象有:字符串.列表.元组 语法:  object[start_index:end_index:step]     以下是创建一个列表 a = [0,1,2 ...

  3. 使用Django的时候,页面请求正常,也没有报任何错误,甚至连警告都没有的情况下,页面却还是原地不动或者闪一下或者无限显示加载动画的情况下的解决办法

    这个问题描述比较笼统,但根据我目前遇到过两种情况来看,似乎都比较重要而且实用,所以打算分别讲述一下. 说明:Django的版本是Django2.0 第一种:URL配置错误 页面闪一下,却原地不动,可能 ...

  4. 前言:JNI调用-简单使用

    JNI JNI是(Java Native Interface  本地接口)是一个协议,用来沟通Java 代码和C/C++代码,是 Java和 C.C++之间的桥梁. 通过JNI协议,Java可以调用外 ...

  5. 用Java开发一个工具类,提供似于js中eval函数功能的eval方法

    今天在看到<Java疯狂讲义>中一个章节习题: 开发一个工具类,该工具类提供一个eval()方法,实现JavaScript中eval()函数的功能--可以动态运行一行或多行程序代码.例如: ...

  6. RabbitMQ 保证消息不丢失

    参考:https://www.imooc.com/article/49814 发送消息的时候,加上messageId字段,数据库记录消息日志表 ,插入的时候为发送中 当收到消息的时候,更改为已发送 , ...

  7. Ubuntu 备份系统为ISO镜像 & 解决ISO限制4GB大小 & Clone当前系统到其他电脑

    看标题,标题涵盖了3个部分,Ubuntu 备份系统为ISO镜像,  解决ISO限制4GB大小 ,  Clone当前系统到其他电脑  我们就从三个部分说起. Ubuntu 备份系统为ISO镜像 在Win ...

  8. C++ 初读vector

    vector 向量(Vector)是一个封装了动态大小数组的顺序容器(Sequence Container).跟任意其它类型容器一样,它能够存放各种类型的对象. Character 高效 C++标准要 ...

  9. kali渗透-基础篇

    渗透之meterpreter 模拟场景:小明是我室友,整天游戏人生,浑浑噩噩,前途迷茫,每次上课交作业都要看我的,于是我开启了apche服务器,给他下载作业(别问我为什么不用QQ传,因为要装逼!),他 ...

  10. Windows10用fiddler抓包Android应用(解决手机设置代理后无法上网,设置只抓app包)

    1.环境准备 1.电脑上安装fiddler 2.手机和电脑在同一个局域网内 2.设置 1.fiddler>Tools>Fiddler Options>Connections 勾选Al ...