zoukankan      html  css  js  c++  java
  • 最长公共子序列

    想要了解最长公共子序列首先要清楚这些概念:

    <1> 子序列:就是在原序列中找出一部分组成的序列。 例:字符串“abcdefg” 的子序列有 “ac”、“ade”....一共有27个子序列

    <2> 最长公共子序列:一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。

               例:字符串“cnblogs”和“belong”的最长公共子序列为“blog”。

               仔细想想我们可以发现其实最长公共子序列的个数不是唯一的,可能会有两个以上,

               但是长度一定是唯一的,比如这里的最长公共子序列的长度为4。

    <3> 子串:串中任意个连续的字符组成的子序列称为该串的子串

    <4> 最长公共子串:两个字符串中,最长的相同子字符串的长度

    最长公共子串(Longest Common Substirng)和最长公共子序列(Longest Common Subsequence,LCS)的区别为:

          子串是串的一个连续的部分,子序列则是从不改变序列的顺序,而从序列中去掉任意的元素而获得新的序列;也就是说,子串中字符的位置必须是连续的,子序列则可以不必连续。

    最长公共子序列的应用:最长公共子序列是一个十分实用的问题,它可以描述两段文字之间的“相似度”,

               即它们的雷同程度,从而能够用来辨别抄袭。对一段文字进行修改之后,

               计算改动前后文字的最长公共子序列,将除此子序列外的部分提取出来,

               这种方法判断修改的部分,往往十分准确。简而言之,百度知道、百度百科都用得上。

    解决最长公共子序列问题 最好的选择 ---> “动态规划”

    动态规划的计算两个序列的最长公共子序列的方法如下:

    以两个序列 s1、s2 为例子:

    设有二维数组x[i,j] 表示 s1 的 i 位和 s2 的 j 位之前的最长公共子序列的长度,则有:

    x[1][1] = same(1,1);

    x[i,j] = max{x[i-1][j -1] + same(i,j),x[i-1,j],x[i,j-1]}

    其中,same(a,b)当 X 的第 a 位与 Y 的第 b 位相同时为“1”,否则为“0”。

    此时,二维数组中最大的数便是 s1 和 s2 的最长公共子序列的长度,依据该数组回溯,便可找出最长公共子序列。

    该算法的空间、时间复杂度均为O(n^2),经过优化后,空间复杂度可为O(n)。

     1 #include <stdio.h>
     2 #include <string.h>
     3 
     4 char s1[1000],s2[1000];
     5 int x[1000][1000];   // 记录最长公共子序列 
     6 int y[1000][1000];   // 记录路径 
     7 int LCS()    
     8 {
     9     int i,j;
    10     int l1 = strlen(s1);     // 计算字符串的长度 
    11     int l2 = strlen(s2);
    12     memset(x,0,sizeof(x));  // 初始化 过滤掉0的情况 
    13     memset(y,0,sizeof(y));
    14     
    15     for (i = 1; i <= l1; i ++)
    16     {
    17         for (j = 1; j <= l2; j ++)
    18         {
    19             if (s1[i-1] == s2[j-1])   // 相等的情况 
    20             {   // 字符数组是从0开始的 所以这里要减 1 
    21                 x[i][j] = x[i-1][j-1]+1;
    22                 y[i][j] = 1;          // 记录路径 
    23             }
    24             else if(x[i-1][j] >= x[i][j-1])    // 不相等的时候选择 比较“左边”和“上边”选择较大的 
    25             {
    26                 x[i][j] = x[i-1][j];
    27                 y[i][j] = 2;          // 记录路径 
    28             }
    29             else
    30             {
    31                 x[i][j] = x[i][j-1];
    32                 y[i][j] = 3;         // 记录路径 
    33             }
    34         }
    35     }
    36     return x[l1][l2];
    37 }
    38 void print_LCS(int i,int j)   // 根据标记路径的数组 输出最长公共子序列 
    39 {
    40     if (i == 0 || j == 0)
    41         return ;
    42     if (y[i][j] == 1)      
    43     {
    44         print_LCS(i-1,j-1);
    45         printf("%c",s1[i-1]);
    46     }
    47     else if (y[i][j] == 2)  // 左边 
    48         print_LCS(i-1,j);
    49     else                    // 上边 
    50         print_LCS(i,j-1);
    51 }
  • 相关阅读:
    hdu1852 Beijing 2008
    hdu-2582 f(n)---找规律+素数筛法
    hdu-1452 Happy 2004---因子和+逆元
    LightOJ-1028 Trailing Zeroes (I)---因子数目
    hdu1215 七夕节---因子和
    因子和&&因子数
    hdu-1492 The number of divisors(约数) about Humble Numbers---因子数公式
    hdu-2136 Largest prime factor---巧用素数筛法
    欧拉函数
    BZOJ4418: [Shoi2013]扇形面积并
  • 原文地址:https://www.cnblogs.com/yoke/p/6686898.html
Copyright © 2011-2022 走看看