请先通过维基百科或其他搜索引擎了解如下知识点,如果已经掌握可直接跳过:

【参考网址:

http://en.wikipedia.org/wiki/Standard_Template_Library

http://www.geeksforgeeks.org/dynamic-programming-set-4-longest-common-subsequence/

1. 最长公共子序列 ;

2. 最长公共子序列与最长公共子串的区别;

 Longest Common Subsequence / Longest Common Substring

3. 求解最长公共子序列的动态规划的算法;

可用动态规划算法求解的问题一般具有两个特点:

1)重叠子问题;

2)最优子结构;

4. 通常用动态规划算法先求最长公共子序列的长度,并将所有子问题的解都保存在一个二维数组中。

例如:

字符串X: abcabcaa

字符串Y: acbacba

m = |X| = 8

n = |Y| = 7

递推表达式:

保存子问题的解(Tabulation)

a c b a c b a
0 0 0 0 0 0 0 0
a 0 1 1 1 1 1 1 1
b 0 1 1 2 2 2 2 2
c 0 1 2 2 2 3 3 3
a 0 1 2 2 3 3 3 4
b 0 1 2 3 3 3 4 4
c 0 1 2 3 3 4 4 4
a 0 1 2 3 4 4 4 5
a 0 1 2 3 4 4 4 5

LCS(X,Y) = 5

输出所有的最长公共子序列:

例子:

字串 X = “abcabcaa" 

字串 Y = "acbacba",

它们的所有最长公共子序列:

ababa
abaca
abcba
acaba
acaca
acbaa
acbca

1)按照O(mn)动态规划的算法求出最长公共子序列的长度

子问题的解保存在二维数组dp里
dp[i][j] = { 字串 X 的 1~i 部分与字串 Y 的 1~j 部分的最长公共子序列的长度 }

2)构造字母表

S = { i | i in X or i in Y }

字母表S由出现在字串X和字串Y的所有字符构成的集合。

前面例子中 X 与 Y 构成的字母表S = "abc"。

3)字母表中的字符在两个字串中最后出现的下标

概念可参考Java中String类的lastIndexOf()方法

last1[i][j] = { 到字串 X 下标 i 为止,字母表第 j 个字符在字串 X 中最后一次出现的下标 }
last2[i][j] = { 到字串 Y 下标 i 为止,字母表第 j 个字符在字串 Y 中最后一次出现的下标 }

4)枚举最长公共字串的每一个字符

从两个字串的长度 len1 和 len2 开始枚举字母表 S 中的每一个字符

例如,

t1 = last1[len1][0]

t2 = last2[len2][0]

表示字母表第0个字符在 X 字符串1---len1的最大下标为t1,

在Y 字符串1--len2的最大下标为t2。

若dp[t1][t2] 的值为s1和s2的最大公共子序列长度 cnt , 则表示这个字符即字母表的第0个字符是最长公共子序列的最后一个字符,

并且继续在 t1 - 1 和 t2 - 1 的子问题中寻找符合最大公共子序列长度为为cnt - 1的字符串,依此类推,直到达最长公共子序列为0时结束。

把保存的字符串放入set集合里面,让它按字典序排序;否则继续枚举字母表中的下一个字符。

为什么从最长公共子序列的最后一个字符开始寻找呢?

例如:

”CDCD"

"FUCKC"

它们构成的字母表S = ”UDFCK"
现在枚举字符'C',它在字母表S中的下标 = 3

last1[0][3] = 0 //下标从0开始

last1[3[3] = 2

last2[2][3] = 2

last2[4][3] = 4

根据’C'在两个字串出现的位置,共有(0, 2)、(0, 4)、 (2, 2) 、(2, 4) 四种可能。

我们舍弃前三个,可以为后续的枚举提供更大的空间。

5)Java语言实现

import java.util.*;/*** The string "abcabcaa" and "acbacba" have longest common subsequences:* ababa* abaca* abcba* acaba* acaca* acbaa* acbca* @author York**/public class LongestCommonSubsequence {String source;String target;int[][] c;int[][] last1;int[][] last2;int lcsLength;char[] tmp;String alphabet;HashSet<String> set = new HashSet<String>();public LongestCommonSubsequence() {}public LongestCommonSubsequence(String s, String t) {this.source = s;this.target = t;}public int LCSLength() {int m = source.length();int n = target.length();c = new int[m+1][n+1];c[0][0] = 0;for(int i = 1; i <= m; ++i) {c[i][0] = 0;}for(int j = 1; j <= n; ++j) {c[0][j] = 0;}for(int i = 1; i <= m; i++) {for(int j = 1; j <= n; j++) {if(source.charAt(i-1) == target.charAt(j-1)) {c[i][j] = c[i-1][j-1] + 1;} else if(c[i-1][j] >= c[i][j-1]){c[i][j] = c[i-1][j];} else {c[i][j] = c[i][j-1];}}}return lcsLength = c[m][n];}private void lastIndexOf(String s, int[][] last) {for (int j = 0; j < alphabet.length(); ++j) {char c = alphabet.charAt(j);for (int i = 1; i <= s.length(); ++i) {int lastIndex;for (lastIndex = i; lastIndex >= 1; --lastIndex) {if(c == s.charAt(lastIndex-1)) {last[i][j] = lastIndex;break;}}if(lastIndex <= 0) {last[i][j] = 0;}}}}private void backTraceAll(int index1, int index2, int len) {if(len <= 0) {String str = new String(tmp);System.out.println("lcs: " + str);set.add(str);return;}if(index1 > 0 && index2 > 0) {for(int j = 0; j < alphabet.length(); ++j) {//字母表中第j个字符最后一次出现在子串source(0, index1)的下标int t1 = last1[index1][j];int t2 = last2[index2][j];//数学证明是?或者给出递归表达式吧if(c[t1][t2] == len) {tmp[len-1] = alphabet.charAt(j);backTraceAll(t1-1, t2-1, len-1);}}}}public void printAll() {int m = source.length();int n = target.length();//由两个字符串构成的字母表,包含它们中出现过的所有字符的集合//alphabet = {i| i in source or target};HashSet<Character> alpha = new HashSet<Character>();for(int i = 0; i < m; ++i) {alpha.add(source.charAt(i));}for(int j = 0; j < n; ++j) {alpha.add(target.charAt(j));}int length = alpha.size();Character[] characters = new Character[length];alpha.toArray(characters);char[] chars = new char[length];for(int i = 0; i < length; ++i) {chars[i] = characters[i];}alphabet = new String(chars);System.out.println("alphabet = " + alphabet);last1 = new int[m+1][alphabet.length()];last2 = new int[n+1][alphabet.length()];System.out.println("c[][]: ");for(int i = 0; i <= m; ++i) {for(int j = 0; j <= n; ++j) {System.out.print(c[i][j] + "\t");}System.out.println();}lastIndexOf(source, last1);lastIndexOf(target, last2);System.out.println("last1[][]: ");for(int i = 0; i <= m; ++i) {for(int j = 0; j < alphabet.length(); ++j) {System.out.print(last1[i][j] + " ");}System.out.println();}System.out.println("last2[][]: ");for(int i = 0; i <= n; ++i) {for(int j = 0; j < alphabet.length(); ++j) {System.out.print(last2[i][j] + " ");}System.out.println();}System.out.println("lcs length = " + lcsLength);tmp = new char[lcsLength];backTraceAll(m, n, lcsLength);System.out.println("All longest common sequences: ");for(String s: set) {System.out.println(s);}}public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("Enter two strings:");String str1 = sc.nextLine();String str2 = sc.nextLine();LongestCommonSubsequence lcs = new LongestCommonSubsequence(str1, str2);int max = lcs.LCSLength();System.out.println("longest length = " + max);lcs.printAll();}
}

参考网址:

http://blog.csdn.net/tsaid/article/details/6726698

http://blog.csdn.net/xiaoxiaoluo/article/details/8169533

http://www.cppblog.com/varg-vikernes/archive/2010/09/27/127866.html

输出所有的最长公共子序列相关推荐

  1. 算法:最长公共子序列(输出所有最长公共子序列)

    问题描述:给定两个序列,例如 X = "ABCBDAB".Y = "BDCABA",求它们的最长公共子序列的长度. 下面是求解时的动态规划表,可以看出 X 和 ...

  2. 实验三、最长公共子序列(输出所有最长公共子序列)

    实验3.最长公共子序列 问题描述与实验目的: 序列Z=<B,C,D,B>是序列X=<A,B,C,B,D,A,B>的子序列,相应的递增下标序列为<2,3,5,7>. ...

  3. java实现最长连续子序列_最长公共子序列 ||

    问题:在 前一篇文章 最长公共子序列 | 的基础上要求将所有的最长公共子序列打印出来,因为最长公共子序列可能不只一种. 难点:输出一个最长公共子序列并不难,难点在于输出所有的最长公共子序列,我们需要在 ...

  4. 触类旁通,经典面试题最长公共子序列应该这么答

    作者 |  labuladong 来源 | labuladong(ID:labuladong) [导读]最长公共子序列(Longest Common Subsequence,简称 LCS)是一道非常经 ...

  5. 最长公共子序列 nyoj-36

    最长公共子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列. tip:最长公共子序列也称作最长 ...

  6. 最长公共子序列LCS

    输入: str1 = "abcde", str2 = "ace" 输出: 3 解释: 最长公共子序列是 "ace",它的长度是 3 这里用0 ...

  7. 算法知识之最长公共子序列问题(动态规划)

    最近朋友让帮做个关于动态规划的最长公共子序列的问题,翻看以前的笔记并完成该题后,顺便写这样一篇文章,希望对大家有所帮助,同时也帮助自己回顾该知识点. 一.最长公共子序列的定义 子序列:若给定序列X={ ...

  8. 10.31T4 HAOI2010最长公共子序列 计数+容斥原理

    2775 -- [HAOI2010]最长公共子序列 Description 字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序 ...

  9. 助你深刻理解——最长公共子串、最长公共子序列(应该是全网数一数二的比较全面的总结了)

    往事不堪回首,那些年处理过的字符串[的一些骚操作] 最长公共子串篇(20191120) 理论知识: 图形理解: 矩阵初始化: 矩阵数值演变: 类似算法: 代码实现(C++): 代码设计满足的要求: 测 ...

最新文章

  1. 第二十三课.Kaggle交易预测
  2. linux sh文件case,Shell脚本case语句简明教程
  3. Linux系统编程(一)
  4. Simulink之多重逆变电路
  5. Linux 下SVN安全及权限配置
  6. 背包九讲----02完全背包问题
  7. 破解XP 管理员Administrator密码
  8. 银行招聘笔试计算机知识,【银行招聘】银行考试笔试中的综合知识考什么?
  9. C++打开网页,发起QQ对话,调用外部exe程序
  10. 【vue】vue中axios的使用及vue生命周期详解_07
  11. 方程组通解的参数向量形式、基本变量和自由变量
  12. 【需求】Python利用selenium抓取顺丰的地址数据
  13. 小白学习之路,网络编程(上)
  14. SYN8086语音合成芯片(TTS语音芯片)各项指标测试已完成,正式批量化生产
  15. 视频APP源码,支持第三方支付,卡密充值,
  16. hibernate的hql查询语句总结
  17. c++飞扬的小鸟1.0正式版
  18. QQ通信原理--转载
  19. 家用游戏机的历史:世嘉、任天堂和 PlayStation 的故事
  20. python按列名删除某列_python-根据熊猫中的列名删除多个列

热门文章

  1. python实现括号匹配算法_Python实现括号匹配方法详解
  2. Task 07--面向对象的编程
  3. (Java生产者消费者问题)http://blog.csdn.net/jhj735412/article/details/6931135
  4. 51Nod-1299-监狱逃离
  5. Python直男作死篇:生日蛋糕小游戏
  6. 计算机大赛志愿者心得体会,志愿者的心得体会
  7. 游戏中子弹的回收重用
  8. JavaSSM笔记(二)SpringMvc基础
  9. Android内、外存储 易混淆点剖析(/mnt/sdcard、/storage/sdcard0、/storage/emulated/0等区别)
  10. 明明白白学通C语言 二维码版 pdf