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


    所谓一个字符串的子序列是指:从该序列中删除若干元素后所得到的序列;如hold为 helloworld的子序列。

    考虑最长公共子序列问题如何分解成子问题,设A=“a0,a1,…,am-1”,B=“b0,b1,…,bm-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” 的一个最长公共子序列。

    这样,在找A和B的公共子序列时,如有am-1=bn-1,则进一步解决一个子问题,找“a0,a1,…,am-2”和“b0,b1,…,bm-2”的一个最长公共子序列;

    如果am-1!=bn-1,则要解决两个子问题,找出“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一个最长公共子序列和找出“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一个最长公共子序列,再取两者中较长者作为A和B的最长公共子序列。

    定义lcs[i][j]为序列“a0,a1,…,ai-1”和“b0,b1,…,bj-1”的最长公共子序列的长度,计算lcs[i][j]可递归地表述如下:

    (1)lcs[i][j] = 0                                如果i=0或j=0;

    (2)lcs[i][j] = lcs[i-1][j-1]+1                如果i,j>0,且a[i-1] = b[j-1];

    (3)lcs[i][j] = max{lcs[i][j-1], lcs[i-1][j]} 如果i,j>0,且a[i-1] != b[j-1]。

    按此算式可写出计算两个序列的最长公共子序列的长度函数。由于lcs[i][j]的产生仅依赖于lcs[i-1][j-1]、lcs[i-1][j]和lcs[i][j- 1],故可以从lcs[m][n]开始,跟踪lcs[i][j]的产生过程,逆向构造出最长公共子序列。细节见程序。

     1 package lcs;
     2 
     3 public class LCS {
     4     private static void ComSubStr(String str1,String str2){
     5         char[] a=str1.toCharArray();
     6         char[] b=str2.toCharArray();
     7         int aLen=a.length;
     8         int bLen=b.length;
     9         int[][] lcs=new int[aLen+1][bLen+1];
    10         
    11         for(int i=0;i<=aLen;i++)
    12             for(int j=0;j<=bLen;j++)
    13                 lcs[i][j]=0;
    14         
    15         for(int i=1;i<=aLen;i++)
    16             for(int j=1;j<=bLen;j++)
    17             {
    18                 if(a[i-1]==b[j-1])
    19                     lcs[i][j]=lcs[i-1][j-1]+1;
    20                 else {
    21                     lcs[i][j]=lcs[i][j-1]>lcs[i-1][j]?lcs[i][j-1]:lcs[i-1][j];
    22                 }
    23             }
    24         
    25         for(int i=0;i<=aLen;i++)
    26         {
    27             for(int j=0;j<=bLen;j++)
    28             {
    29                 System.out.print(lcs[i][j]+",");
    30             }
    31             System.out.println();
    32         }
    33         
    34         int maxLen=lcs[aLen][bLen];
    35         int i=aLen;
    36         int j=bLen;
    37         char[] comSubStr=new char[maxLen];
    38         while(maxLen>0)
    39         {
    40             if(lcs[i][j]!=lcs[i-1][j-1])//说明a0......ai-1,b0.......bj-1中ai-1或bj-1为公共的;
    41             {
    42                 if(lcs[i][j-1]==lcs[i-1][j])//说明ai-1=bj-1为公共字符;
    43                 {
    44                     comSubStr[maxLen-1]=a[i-1];
    45                     maxLen--;
    46                     i--;
    47                     j--;
    48                 }
    49                 else{//取两者中较长的作为a,b,的公共子序列
    50                     if(lcs[i][j-1]>lcs[i-1][j])
    51                         j--;
    52                     else {
    53                         i--;
    54                     }
    55                 }
    56             }
    57             else{
    58                 i--;
    59                 j--;
    60             }
    61         }
    62         System.out.print("最长公共字符串是:");
    63         System.out.println(comSubStr);
    64     }
    65     public static void main(String[] args){
    66         String a = "blog.csdn.net";  
    67         String b = "csdn.blogt";
    68         LCS.ComSubStr(a, b);
    69     }
    70 }

    输出结果为:

    0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,1,1,1,1,1,
    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
    

      

  • 相关阅读:
    P1587 [NOI2016]循环之美 杜教筛
    【学习笔记】省选动态规划类型选讲
    【模板】结构体重载高精度
    SP1716 GSS3
    SP1043 GSS1
    P1890 gcd区间 线段树
    【模板】(最小费用)最大流
    【模板】矩阵乘法
    P1073 最优贸易 DFS
    【2019.8.14】2019QB学堂DP图论班第一次考试 Problem C
  • 原文地址:https://www.cnblogs.com/enjoy-life-clh/p/4795217.html
Copyright © 2020-2023  润新知