LCS问题(最长公共子序列)-动态规划实现

问题描述:

问题】 求两字符序列的最长公共字符子序列

注意:

并不要求子串(字符串一)的字符必须连续出现在字符串二中。

思路分析:

最优子结构和重叠子问题的性质都具有,所以要采取动态规划的算法

最长公共子序列的结构

设序列X=

其中Xm-1=

子问题的递归结构

由最长公共子序列问题的最优子结构性质可知,要找出X=

由此递归结构容易看到最长公共子序列问题具有子问题重叠性质。

例如,在计算X和Y的最长公共子序列时,可能要计算出X和Yn-1及Xm-1和Y的最长公共子序列。而这两个子问题都包含一个公共子问题,即计算Xm-1和Yn-1的最长公共子序列。

与矩阵连乘积最优计算次序问题类似,我们来建立子问题的最优值的递归关系。用c[i,j]记录序列Xi和Yj的最长公共子序列的长度。其中Xi=<x1, x2, …, xi>,Yj=<y1, y2, …, yj>。

当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故c[i,j]=0。其他情况下,由定理可建立递归关系如下:

代码:

public class ComSubstr {  

    public static void main(String[] arg) {
        String a = "blog.csdn.net";
        String b = "csdn.blogt";
        comSubstring(a, b);
    }  

    private static void comSubstring(String str1, String str2) {
        char[] a = str1.toCharArray();
        char[] b = str2.toCharArray();
        int a_length = a.length;
        int b_length = b.length;
        int[][] lcs = new int[a_length + 1][b_length + 1];
        // 初始化数组
        for (int i = 0; i <= b_length; i++) {
            for (int j = 0; j <= a_length; j++) {
                lcs[j][i] = 0;
            }
        }
        for (int i = 1; i <= a_length; i++) {
            for (int j = 1; j <= b_length; j++) {
                if (a[i - 1] == b[j - 1]) {
                    lcs[i][j] = lcs[i - 1][j - 1] + 1;
                }
                if (a[i - 1] != b[j - 1]) {
                    lcs[i][j] = lcs[i][j - 1] > lcs[i - 1][j] ? lcs[i][j - 1]
                            : lcs[i - 1][j];
                }
            }
        }
        // 输出数组结果进行观察
        for (int i = 0; i <= a_length; i++) {
            for (int j = 0; j <= b_length; j++) {
                System.out.print(lcs[i][j]+",");
            }
            System.out.println("");
        }
        // 由数组构造最小公共字符串
        int max_length = lcs[a_length][b_length];
        char[] comStr = new char[max_length];
        int i =a_length, j =b_length;
        while(max_length>0){
            if(lcs[i][j]!=lcs[i-1][j-1]){
                if(lcs[i-1][j]==lcs[i][j-1]){//两字符相等,为公共字符
                    comStr[max_length-1]=a[i-1];
                    max_length--;
                    i--;j--;
                }else{//取两者中较长者作为A和B的最长公共子序列
                    if(lcs[i-1][j]>lcs[i][j-1]){
                        i--;
                    }else{
                        j--;
                    }
                }
            }else{
                i--;j--;
            }
        }
        System.out.print("最长公共字符串是:");
        System.out.print(comStr);
    }
}

输出结果:

0,0,0,0,0,0,1,2,2,2,2,
0,0,0,0,0,0,1,2,3,3,3,
0,0,0,0,0,0,1,2,3,4,4,
0,0,0,0,0,1,1,2,3,4,4,
0,1,1,1,1,1,1,2,3,4,4,
0,1,2,2,2,2,2,2,3,4,4,
0,1,2,3,3,3,3,3,3,4,4,
0,1,2,3,4,4,4,4,4,4,4,
0,1,2,3,4,5,5,5,5,5,5,
0,1,2,3,4,5,5,5,5,5,5,
0,1,2,3,4,5,5,5,5,5,5,
0,1,2,3,4,5,5,5,5,5,6,
最长公共字符串是:csdn.t  

## 我的微信二维码如下,欢迎交流讨论 ##

欢迎关注《IT面试题汇总》微信订阅号。每天推送经典面试题和面试心得技巧,都是干货!

微信订阅号二维码如下:

参考:

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

http://www.programgo.com/article/74411986718/

时间: 2024-11-08 20:53:28

LCS问题(最长公共子序列)-动态规划实现的相关文章

最长公共子序列---动态规划

一: 作用 最长公共子序列的问题常用于解决字符串的相似度,是一个非常实用的算法,作为码农,此算法是我们的必备基本功. 二:概念 举个例子,cnblogs这个字符串中子序列有多少个呢?很显然有27个,比如其中的cb,cgs等等都是其子序列,我们可以看出 子序列不见得一定是连续的,连续的那是子串. 我想大家已经了解了子序列的概念,那现在可以延伸到两个字符串了,那么大家能够看出:cnblogs和belong的公共子序列吗? 在你找出的公共子序列中,你能找出最长的公共子序列吗? 从图中我们看到了最长公共

C++求解汉字字符串的最长公共子序列 动态规划

    近期,我在网上看了一些动态规划求字符串最长公共子序列的代码.可是无一例外都是处理英文字符串,当处理汉字字符串时.常常会出现乱码或者不对的情况. 我对代码进行了改动.使用wchar_t类型存储字符串,可以正确的处理英文字符串和汉字字符串的最长公共子序列. 代码例如以下: #include "stdafx.h" #include <iostream> #define N 1000 using namespace std; //str1存储字符串1,str2存储字符串2

ACM试题 - 最长公共子序列 - 动态规划方法

ACM试题题源-(最长公共子序列):http://acm.nyist.net/JudgeOnline/problem.php?pid=36 提交代码: import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner cin = new Scanner(System.in); int n = cin.nextInt(); int[] len = new int[n]; fo

LCS求最长公共子序列(DP)

动态规划并不是一种算法,而是一种解决问题的思路.典型的动态规划问题,如最长公共子序列(LCS),最长单调子序列(LIS)等. 动态规划分为四个步骤: 1.判断问题是否具有最优子结构 这里以LCS为例,X={x1,x2,...,xi}:Y={y1,y2,...,yj}.最长公共子序列Z={z1,z2,...,zk}: ①如果xi=yj,那么zk=xi=yj,且Zk-1是序列Xi-1和Yj-1的LCS: ②如果xi≠yj,那么zk≠xi:且Zk是序列Xi-1和Yj的LCS: ③如果xi≠yj,那么z

LCS(最长公共子序列)动规算法正确性证明

今天在看代码源文件求diff的原理的时候看到了LCS算法.这个算法应该不陌生,动规的经典算法.具体算法做啥了我就不说了,不知道的可以直接看<算法导论>动态规划那一章.既然看到了就想回忆下,当想到算法正确性的时候,发现这个算法的正确性证明并不好做.于是想了一段时间,里面有几个细节很trick,容易陷进去.想了几轮,现在把证明贴出来,有异议的可以留言一起交流. 先把一些符号和约定说明下: 假设有两个数组,A和B.A[i]为A的第i个元素,A(i)为有A的第一个元素到第i个元素所组成的前缀.m(i,

最长公共子序列--动态规划入门

求两个序列 X{1,2, 5, 4, ...}和Y{1, 5, 4,,,,}中最长的共有序列. 例如X = {A,B, C, B,D, A, B}, Y={B,D,C,A,B,A} 两者的最长公共子序列为 {B,C,B, A} 分析: 这个问题是否可以分成一段一段处理呢? (即可否找出递归结构, 可见递归很重要, 也许你感觉它很基础,其实它很深奥!).我们从X,Y的最后一个元素来考虑, 若X的最后一个元素在最长子串中(即它对最长子串有贡献), 那么有两种情况, 它和Y的最后一个元素相同, 或它与

最长公共子序列--动态规划算法

考虑最长公共子序列问题如何分解成子问题,设A=“a0,a1,…,am-1”,B=“b0,b1,…,bn-1”,并Z=“z0,z1,…,zk-1”为它们的最长公共子序列.不难证明有以下性质: (1) 如果am-1=bn-1,则zk-1=am-1=bn-1,且“z0,z1,…,zk-2”是“a0,a1,…,am-2”和“b0,b1,…,bn-2”的一个最长公共子序列: (2) 如果am-1!=bn-1,则若zk-1!=am-1,蕴涵“z0,z1,…,zk-1”是“a0,a1,…,am-2”和“b0,

POJ 1458 Common Subsequence (DP+LCS,最长公共子序列)

题意:给定两个字符串,让你找出它们之间最长公共子序列(LCS)的长度. 析:很明显是个DP,就是LCS,一点都没变.设两个序列分别为,A1,A2,...和B1,B2..,d(i, j)表示两个字符串LCS长度. 当A[i] = B[j] 时,这个最长度就是上一个长度加1,即:d(i, j) = d(i-1, j-1) + 1; 当A[i] != B[j] 时,那就是前面的最长长度(因为即使后面的不成立,也不会影响前面的),即:d(i, j) = max{d(i-1, j), d(i, j-1)}

NYOJ 36 LCS(最长公共子序列)

题目链接: http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=36 最长公共子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列. tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条

LCS 求最长公共子序列

最长公共子序列不需要字符连续出现和字串不同 //LCS 求最长公共子串模板题  Common Subsequence 描述 A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = <x1, x2, ..., xm> another sequence Z = <z1, z2, ..., zk> is