动态规划算法之:最长公共子序列 & 最长公共子串(LCS)

1、先科普下最长公共子序列 & 最长公共子串的区别:

找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的。而最长公共子序列则并不要求连续。

2、最长公共子串

其实这是一个序贯决策问题,可以用动态规划来求解。我们采用一个二维矩阵来记录中间的结果。这个二维矩阵怎么构造呢?直接举个例子吧:"bab"和"caba"(当然我们现在一眼就可以看出来最长公共子串是"ba"或"ab")

   b  a  b

c  0  0  0

a  0  1  0

b  1  0  1

a  0  1  0

我们看矩阵的斜对角线最长的那个就能找出最长公共子串。

不过在二维矩阵上找最长的由1组成的斜对角线也是件麻烦费时的事,下面改进:当要在矩阵是填1时让它等于其左上角元素加1。

   b  a  b

c  0  0  0

a  0  1  0

b  1  0  2

a  0  2  0

这样矩阵中的最大元素就是 最长公共子串的长度。

在构造这个二维矩阵的过程中由于得出矩阵的某一行后其上一行就没用了,所以实际上在程序中可以用一维数组来代替这个矩阵。

2.1 代码如下:

public class LCString2 {

public static void getLCString(char[] str1, char[] str2) {

int i, j;

int len1, len2;

len1 = str1.length;

len2 = str2.length;

int maxLen = len1 > len2 ? len1 : len2;

int[] max = new int[maxLen];

int[] maxIndex = new int[maxLen];

int[] c = new int[maxLen]; // 记录对角线上的相等值的个数

for (i = 0; i < len2; i++) {

for (j = len1 - 1; j >= 0; j--) {

if (str2[i] == str1[j]) {

if ((i == 0) || (j == 0))

c[j] = 1;

else

c[j] = c[j - 1] + 1;

} else {

c[j] = 0;

}

if (c[j] > max[0]) { // 如果是大于那暂时只有一个是最长的,而且要把后面的清0;

max[0] = c[j]; // 记录对角线元素的最大值,之后在遍历时用作提取子串的长度

maxIndex[0] = j; // 记录对角线元素最大值的位置

for (int k = 1; k < maxLen; k++) {

max[k] = 0;

maxIndex[k] = 0;

}

} else if (c[j] == max[0]) { // 有多个是相同长度的子串

for (int k = 1; k < maxLen; k++) {

if (max[k] == 0) {

max[k] = c[j];

maxIndex[k] = j;

break; // 在后面加一个就要退出循环了

}

}

}

}

}

for (j = 0; j < maxLen; j++) {

if (max[j] > 0) {

System.out.println("第" + (j + 1) + "个公共子串:");

for (i = maxIndex[j] - max[j] + 1; i <= maxIndex[j]; i++)

System.out.print(str1[i]);

System.out.println(" ");

}

}

}

public static void main(String[] args) {

String str1 = new String("123456abcd567");

String str2 = new String("234dddabc45678");

// String str1 = new String("aab12345678cde");

// String str2 = new String("ab1234yb1234567");

getLCString(str1.toCharArray(), str2.toCharArray());

}

}

ref:

LCS的java算法---考虑可能有多个相同的最长公共子串

http://blog.csdn.net/rabbitbug/article/details/1740557

最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离

http://www.cnblogs.com/zhangchaoyang/articles/2012070.html

2.2 其实 awk 写起来也很容易:

echo "123456abcd567

234dddabc45678"|awk -vFS="" ‘NR==1{str=$0}NR==2{N=NF;for(n=0;n++<N;){s="";for(t=n;t<=N;t++){s=s""$t;if(index(str,s)){a[n]=t-n;b[n]=s;if(m<=a[n])m=a[n]}else{t=N}}}}END{for(n=0;n++<N;)if(a[n]==m)print b[n]}‘

ref:http://bbs.chinaunix.net/thread-4055834-2-1.html

2.3 perl的。。。真心没看懂。。。

#!/usr/bin/perl

use strict;

use warnings;

my $str1 ="123456abcd567";

my $str2 = "234dddabc45678";

my $str = $str1 . "\n" . $str2;

my (@substr,@result);

$str =~ /(.+)(?=.*\n.*\1)(*PRUNE)(?{push @substr,$1})(*F)/;

@substr = sort { length($b) <=> length($a) } @substr;

@result = grep { length == length $substr[0] } @substr;

print "@result\n";

ref: http://bbs.chinaunix.net/thread-1333575-7-1.html

3、最长公共子序列

import java.util.Random;

public class LCS {

public static void main(String[] args) {

// 随机生成字符串

// String x = GetRandomStrings(substringLength1);

// String y = GetRandomStrings(substringLength2);

String x = "a1b2c3";

String y = "1a1wbz2c123a1b2c123";

// 设置字符串长度

int substringLength1 = x.length();

int substringLength2 = y.length(); // 具体大小可自行设置

// 构造二维数组记录子问题x[i]和y[i]的LCS的长度

int[][] opt = new int[substringLength1 + 1][substringLength2 + 1];

// 从后向前,动态规划计算所有子问题。也可从前到后。

for (int i = substringLength1 - 1; i >= 0; i--) {

for (int j = substringLength2 - 1; j >= 0; j--) {

if (x.charAt(i) == y.charAt(j))

opt[i][j] = opt[i + 1][j + 1] + 1;// 状态转移方程

else

opt[i][j] = Math.max(opt[i + 1][j], opt[i][j + 1]);// 状态转移方程

}

}

System.out.println("substring1:" + x);

System.out.println("substring2:" + y);

System.out.print("LCS:");

int i = 0, j = 0;

while (i < substringLength1 && j < substringLength2) {

if (x.charAt(i) == y.charAt(j)) {

System.out.print(x.charAt(i));

i++;

j++;

} else if (opt[i + 1][j] >= opt[i][j + 1])

i++;

else

j++;

}

}

// 取得定长随机字符串

public static String GetRandomStrings(int length) {

StringBuffer buffer = new StringBuffer("abcdefghijklmnopqrstuvwxyz");

StringBuffer sb = new StringBuffer();

Random r = new Random();

int range = buffer.length();

for (int i = 0; i < length; i++) {

sb.append(buffer.charAt(r.nextInt(range)));

}

return sb.toString();

}

}

REF:

字符串最大公共子序列以及最大公共子串问题

http://gongqi.iteye.com/blog/1517447

动态规划算法解最长公共子序列LCS问题

http://blog.csdn.net/v_JULY_v/article/details/6110269

动态规划算法之:最长公共子序列 & 最长公共子串(LCS)

时间: 2024-12-21 13:58:02

动态规划算法之:最长公共子序列 & 最长公共子串(LCS)的相关文章

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

From:http://my.oschina.net/leejun2005/blog/117167 1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的.而最长公共子序列则并不要求连续. 2.最长公共子串 其实这是一个序贯决策问题,可以用动态规划来求解.我们采用一个二维矩阵来记录中间的结果.这个二维矩阵怎么构造呢?直接举个例子吧:"bab"和"caba"(当然我们现在一眼就可以看出来最长公共子串是

算法设计 - LCS 最长公共子序列&amp;&amp;最长公共子串 &amp;&amp;LIS 最长递增子序列

出处 http://segmentfault.com/blog/exploring/ 本章讲解:1. LCS(最长公共子序列)O(n^2)的时间复杂度,O(n^2)的空间复杂度:2. 与之类似但不同的最长公共子串方法.最长公共子串用动态规划可实现O(n^2)的时间复杂度,O(n^2)的空间复杂度:还可以进一步优化,用后缀数组的方法优化成线性时间O(nlogn):空间也可以用其他方法优化成线性.3.LIS(最长递增序列)DP方法可实现O(n^2)的时间复杂度,进一步优化最佳可达到O(nlogn)

动态规划 ---- 最长公共子序列(Longest Common Subsequence, LCS)

分析: 完整代码: // 最长公共子序列 #include <stdio.h> #include <algorithm> using namespace std; const int N = 100; char A[N], B[N]; int dp[N][N]; int main() { freopen("in.txt", "r", stdin); int n; gets(A + 1); // 从下标1开始读入 gets(B + 1); in

最长公共子序列|最长公共子串|最长重复子串|最长不重复子串|最长回文子串|最长递增子序列|最大子数组和

参考:http://www.ahathinking.com/archives/124.html 最长公共子序列 1.动态规划解决过程 1)描述一个最长公共子序列 如果序列比较短,可以采用蛮力法枚举出X的所有子序列,然后检查是否是Y的子序列,并记录所发现的最长子序列.如果序列比较长,这种方法需要指数级时间,不切实际. LCS的最优子结构定理:设X={x1,x2,……,xm}和Y={y1,y2,……,yn}为两个序列,并设Z={z1.z2.……,zk}为X和Y的任意一个LCS,则: (1)如果xm=

LIS LCS 最长上升子序列 最长公共子序列 ...

最长上升子序列,问题定义:http://blog.csdn.net/chenwenshi/article/details/6027086 代码: public static void getData( char[] L ) { int len = L.length; int[] f = new int[len]; String[] res = new String[len]; for( int i = 1; i < len; i++ ) { f[i] = 1; res[i] = "&quo

HDU - 6197 array array array (最长上升子序列&amp;最长下降子序列)

题意:对于一个序列,要求去掉正好K个数字,若能使其成为不上升子序列或不下降子序列,则“A is a magic array.”,否则"A is not a magic array.\n". 分析: 1.求一遍LCS,然后在将序列逆转,求一遍LCS,分别可得最长上升子序列和最长下降子序列的长度tmp1.tmp2. 2.n - tmp1 <= k或n - tmp2 <= k即可,需要去掉的去完之后,在已经是最长上升或最长下降的序列中随便去够k个就好了. #include<

POJ 1836 Alignment(DP max(最长上升子序列 + 最长下降子序列))

Alignment Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 14486   Accepted: 4695 Description In the army, a platoon is composed by n soldiers. During the morning inspection, the soldiers are aligned in a straight line in front of the cap

DP简单问题联系--最长递增子序列+最长公共子序列等

今天重温了一下dp问题,发现自己两个礼拜不写题目就什么都不会了...心态爆炸,感觉去考试怕是要gg了... 不过今天总结一下写的题目,全部都是基础的dp问题 第一个是 求最长不下降子序列的长度 第一行为n,表示n个数 第二行n个数 最长不下降子序列的长度 N小于5000 for  each  num  < =maxint 样例输入 3 1 2 3 样例输出 3 // // Created by 陈平 on 2018/7/8. // #include "iostream" usin

动态规划算法解最长公共子序列LCS问题

第一部分.什么是动态规划算法 ok,咱们先来了解下什么是动态规划算法. 动态规划一般也只能应用于有最优子结构的问题.最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似).简单地说,问题能够分解成子问题来解决. 动态规划算法分以下4个步骤: 描述最优解的结构 递归定义最优解的值 按自底向上的方式计算最优解的值   //此3步构成动态规划解的基础. 由计算出的结果构造一个最优解.   //此步如果只要求计算最优解的值时,可省略. 好,接下来,咱们