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

考虑最长公共子序列问题如何分解成子问题,设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,b1,…,bn-1”的一个最长公共子序列;

(3) 如果am-1!=bn-1,则若zk-1!=bn-1,蕴涵“z0,z1,…,zk-1”是“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一个最长公共子序列。

问题的递归式写成:

回溯输出最长公共子序列过程:

package test;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: LCS
 * @Description: TODO
 * @author:
 * @Date: 2015-06-29 12:50:14
 */
public class LCS {

    static int MAX=2;

    public static List<String> getLCS(int[][] c, int i, int j, String x, String y){
        List<String> t = new ArrayList<String>();
        if(i == 0 || j == 0){
            ;
        }else if(c[i][j] == 1){
            t = getLCS(c,i-1,j-1,x,y);
            if(t.size() == 0)
                t.add("");
            for(int k = 0; k < t.size(); k++){
                String v = t.get(k);
                if(v.length() > 0){
                    int it = Integer.parseInt(v.substring(v.lastIndexOf("(")+1,v.lastIndexOf(",")));
                    if(i - it > 2){
                        t.remove(k);
                        continue;
                    }
                    int jt = Integer.parseInt(v.substring(v.lastIndexOf(",")+1,v.lastIndexOf(")")));
                    if(j - jt > 2){
                        t.remove(k);
                        continue;
                    }
                }
                t.set(k, t.get(k) + x.charAt(i)+"("+i+","+j+")");
            }
        }else if(c[i][j] == 2){
            t = getLCS(c,i-1,j,x,y);
        }else if(c[i][j] == 3){
            t.addAll(getLCS(c,i-1,j,x,y));
            t.addAll(getLCS(c,i,j-1,x,y));
        }else{
            t = getLCS(c,i,j-1,x,y);
        }
        return t;
    }

    public static int LCSLength(int[][] c, int i, int j, byte[] xx, byte[] yy,int[][] max){

        if(i == 0 || j == 0){
            c[i][j] = 0;
        }else if(xx[i] == yy[j]){
            max[i][j] = 1;
            c[i][j] = LCSLength(c,i-1,j-1,xx,yy,max)+1;
        }else {
            int ii = LCSLength(c,i-1,j,xx,yy,max);
            int jj = LCSLength(c,i,j-1,xx,yy,max);
            if(ii > jj)
                max[i][j] = 2;
            else if(ii == jj)
                max[i][j] = 3;

            c[i][j] = Math.max(ii,jj);
        }
        return c[i][j];
    }

    public static void main(String[] args){
        String x = " ABCBDAB";
        String y = " BDCABA";

        byte[] xx = x.getBytes();
        byte[] yy = y.getBytes();

        int c[][] = new int[x.length()][y.length()];
        int max[][] = new int[x.length()][y.length()];
        System.out.println(LCSLength(c,x.length()-1,y.length()-1,xx,yy,max));

        List<String> list  = getLCS(max,x.length()-1,y.length()-1,x,y);
        for(String v: list)
            System.out.println(v);
        System.out.print("\n  ");
        for(int j = 1; j < y.length();j++)
            System.out.print(y.charAt(j)+ " ");
        System.out.println("");
        for(int i = 1; i < x.length(); i++){
            System.out.print(x.charAt(i)+ " ");
            for(int j = 1; j < y.length();j++)
                System.out.print(c[i][j]+ " ");
            System.out.println(" ");
        }

    }
}
时间: 2024-10-03 02:58:20

最长公共子序列--动态规划算法的相关文章

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

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

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

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

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

最长公共子序列--【算法导论】

最长公共子序列:一个序列 S .假设各自是两个或多个已知序列的子序列,且是全部符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列. 其核心非常easy: 这样,构造子结构就比較简单了: if(str1[i - 1] == str2[j - 1]) m[i][j] = m[i - 1][j - 1] + 1; else m[i][j] = max(m[i - 1][j], m[i][j - 1]); 前面动态规划思想说得足够了,这次直接贴: #include <iostream> #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的最后一个元素相同, 或它与

【luogu1439】 【模板】最长公共子序列 [动态规划][LIS最长上升子序列][离散化]

P1439 [模板]最长公共子序列 此思路详见luogu第一个题解 一个很妙的离散化 刘汝佳蓝书上面的LIS 详见蓝书 d[i]以i为结尾的最长上升子序列的长度     g[i]表示d值为i的最小状态的编号即长度为i的上升子序列的最小末尾值 1 for(int i=1;i<=n;++i) scanf("%d",&a[i]); 2 for(int i=1;i<=n;++i) 3 { 4 int k=lower_bound(g+1,g+1+n,a[i])-g; 5 d[

hdu 1159 Common Subsequence(最长公共子序列 动态规划)

Common Subsequence Problem Description 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 a subsequence of X if

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

最长公共子序列也是动态规划中的一个经典问题. 有两个字符串 S1 和 S2,求一个最长公共子串,即求字符串 S3,它同时为 S1 和 S2 的子串,且要求它的长度最长,并确定这个长度.这个问题被我们称为 最长公共子序列问题. 与求最长递增子序列一样,我们首先将原问题分割成一些子问题,我们用 dp[i][j]表示 S1 中前 i 个字符与 S2 中前 j 个字符分别组成的两个前缀字符串的最 长公共子串长度. 显然的,当 i. j 较小时我们可以直接得出答案,如 dp[0][j]必 等于 0.那么,

动态规划求解最长公共子序列

动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解.与分治法不同的是,适合于用动态规划求解的问题,经分解得到的子问题往往不是互相独立的.若用分治法来解决这类问题,则分解得到的子问题数目太多,以至于最后解决原问题需要耗费指数时间.然而,不同子问题的数目常常只有多项式量级.在用分治法求解时,有些子问题被重复计算了许多次.如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,从而得到多项式