zoukankan      html  css  js  c++  java
  • 《算法导论》CLRS算法C++实现(十二)P208 最长公共子序列LCS

    给定两个序列X和Y,如果Z既是X的一个子序列又是Y的一个子序列,则称序列Z是X和Y的一个公共子序列。

    在最长公共子序列问题(LCS)中,给定了两个序列X=<x1,x2,…,xm>和Y=<y1,y2,…,yn>,希望找出X和Y的最大长度的公共子序列。最直观且容易想到的方法是枚举出X的所有子序列,然后逐一检查看其是否为Y的子序列,并随时记录所发现的最长子序列。这种方法的时间复杂度是指数级的,对于较长的序列来说是不实际的。

    LCS问题的最优子结构:

    若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的最长公共子序列;
    若xm≠yn且zk≠xm ,则Z是Xm-1和Y的最长公共子序列;
    若xm≠yn且zk≠yn ,则Z是X和Yn-1的最长公共子序列。

    算法:LCS-LENGTH(X, Y)

    复制代码
     1  2 m ← length[X]
     3 n ← length[Y]
     4 for i ← 1 to m
     5       do c[i, 0] ← 0
     6 for j ← 0 to n
     7     do c[0, j] ← 0
     8 for i ← 1 to m
     9     do for j ← 1 to n
    10             do if xi = yj
    11                    then c[i, j] ← c[i - 1, j - 1] + 1
    12                         b[i, j] ← ""
    13                    else if c[i - 1, j] ≥ c[i, j - 1]
    14                           then c[i, j] ← c[i - 1, j]
    15                                b[i, j] ← ""
    16                           else c[i, j] ← c[i, j - 1]
    17                                b[i, j] ← ←
    18 return c and b
    复制代码

    C++实现:

    复制代码
      1 #include <iostream>
      2 #include <stdio.h>
      3 #include <string.h>
      4 
      5 using namespace std;
      6 
      7 enum
      8 dir {dInit = 0, dLeft, dUp, dUpLeft};//定义方向初始化值dInit,三个方向左dLeft、上dUp、左上dUpLeft
      9 
     10 void LCSPrint(int **LCS_direction, const char* la, const char* lb, int row, int col)
     11 {
     12     if (la == NULL || lb == NULL)
     13         return;
     14 
     15     int lengthA = strlen(la);
     16     int lengthB = strlen(lb);
     17 
     18     if (lengthA ==0 || lengthB == 0 || !(row < lengthA && col < lengthB))
     19         return;
     20 
     21     if (LCS_direction[row][col] == dUpLeft)
     22     {
     23         if (row > 0 && col > 0)
     24             LCSPrint(LCS_direction, la, lb, row - 1, col - 1);
     25 
     26         printf("%c", la[row]);
     27     }
     28     else if (LCS_direction[row][col] == dUp)
     29     {
     30         if (row > 0)
     31             LCSPrint(LCS_direction, la, lb, row - 1, col);
     32     }
     33     else if(LCS_direction[row][col] == dLeft)
     34     {
     35         if (col > 0)
     36             LCSPrint(LCS_direction, la, lb, row, col - 1);
     37     }
     38 }
     39 
     40 int
     41 LCSLength(const char *la, const char *lb)
     42 {
     43     if (!la || !lb)
     44         return 0;
     45 
     46     int lengthA = strlen(la);
     47     int lengthB = strlen(lb);
     48 
     49     if (!lengthA || !lengthB)
     50         return 0;
     51 
     52     int i, j;
     53 
     54     //创建并初始化存放长度的二维数组
     55     int **LCS_length;
     56     LCS_length = (int**)(new int[lengthA]);
     57     for (i = 0; i < lengthA; ++i)
     58         LCS_length[i] = (int*)new int[lengthB];
     59 
     60     for (i = 0; i < lengthA; ++i)
     61         for (j = 0; j < lengthB; ++j)
     62             LCS_length[i][j] = 0;
     63 
     64     //创建并初始化存放方向的二维数组,方向在枚举enum dir中定义
     65     int **LCS_direction;
     66     LCS_direction = (int**)(new int[lengthA]);
     67     for (i = 0; i < lengthA; ++i)
     68         LCS_direction[i] = (int*)new int[lengthB];
     69 
     70     for (i = 0; i < lengthA; ++i)
     71         for (j = 0; j < lengthB; ++j)
     72             LCS_direction[i][j] = dInit;
     73 
     74     for (i = 0; i < lengthA; ++i)
     75     {
     76         for (j = 0; j < lengthB; ++j)
     77         {
     78             if (i == 0 || j == 0)
     79             {
     80                 if (la[i] == lb[j])
     81                 {
     82                     LCS_length[i][j] = 1;
     83                     LCS_direction[i][j] = dUpLeft;
     84                 }
     85                 else
     86                 {
     87                     if (i > 0)
     88                     {
     89                         //i > 0不是第一行
     90                         LCS_length[i][j] = LCS_length[i - 1][j];
     91                         LCS_direction[i][j] = dUp;
     92                     }
     93                     if (j > 0)
     94                     {
     95                         //j > 0不是第一列
     96                         LCS_length[i][j] = LCS_length[i][j - 1];
     97                         LCS_direction[i][j] = dLeft;
     98                     }
     99                 }
    100             }
    101 
    102             else if (la[i] == lb[j])
    103             {
    104                 LCS_length[i][j] = LCS_length[i - 1][j - 1] + 1;
    105                 LCS_direction[i][j] = dUpLeft;
    106             }
    107 
    108             else if (LCS_length[i - 1][j] > LCS_length[i][j - 1])
    109             {
    110                 LCS_length[i][j] = LCS_length[i - 1][j];
    111                 LCS_direction[i][j] = dUp;
    112             }
    113 
    114             else
    115             {
    116                 LCS_length[i][j] = LCS_length[i][j - 1];
    117                 LCS_direction[i][j] = dLeft;
    118             }
    119         }
    120     }
    121     LCSPrint(LCS_direction, la, lb, lengthA - 1, lengthB - 1);
    122     cout << endl;
    123     return LCS_length[lengthA - 1][lengthB - 1];
    124 }
    125 
    126 int main()
    127 {
    128     const char* la = "ABCBDAB";
    129     const char* lb = "BDCABA";
    130     int length = LCSLength(la, lb);
    131     cout << "最长子序列长度为:" << length << endl;
    132     return 0;
    133 }
    复制代码

    Python实现:

    复制代码
     1 def LCS(la, lb):
     2     if la == "" or lb == "":
     3         return
     4     lengthA = len(la)
     5     lengthB = len(lb)
     6     lcs = [[0] for i in range(0, lengthA + 1)]
     7     lcs[0] = [0 for j in range(0, lengthB + 1)]
     8     for i in range(lengthA):
     9         for j in range(lengthB):
    10             lcs[i + 1].append(lcs[i][j] + 1 if la[i] == lb[j] else max(lcs[i][j + 1], lcs[i + 1][j]))
    11     i = lengthA - 1
    12     j = lengthB - 1
    13     lcsstr = ""
    14     while True:
    15         if i == -1 or j == -1:
    16             break
    17         if la[i] == lb[j]:
    18             lcsstr = "%s%s" % (la[i], lcsstr)
    19             i = i - 1
    20             j = j - 1
    21         else:
    22             if lcs[i][j + 1] > lcs[i + 1][j]:
    23                 i = i - 1
    24             else:
    25                 j = j - 1
    26     print lcsstr
    27     
    28 LCS("ABCBDAB", "BDCABA")
    复制代码

     

     
     
  • 相关阅读:
    关于VSCode如何缩进两个空格
    基于vue来开发一个仿饿了么的外卖商城(二)
    在复杂的项目开发中使用结对编程
    第一个博客
    docker容器启动失败解决办法
    windows转mac-开发环境搭建(六):mac上搭建git环境
    windows转mac-开发环境搭建(五):mac上用docker安装并运行mysql
    windows转mac-开发环境搭建(四):mac上搭建node、VS code、idea环境
    windows转mac-开发环境搭建(三):mac上搭建maven环境
    windows转mac-开发环境搭建(二):mac上搭建java环境
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2608774.html
Copyright © 2011-2022 走看看