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

    1、先科普下最长公共子序列 & 最长公共子串的区别:

    找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的。而最长公共子序列则并不要求连续。

    (1)递归方法求最长公共子序列的长度

        1)设有字符串a[0...n],b[0...m],下面就是递推公式。

                 当数组a和b对应位置字符相同时,则直接求解下一个位置;当不同时取两种情况中的较大数值。

        

        2)代码如下:

     1 #include<stdio.h>
     2 #include<string.h>
     3 char a[30],b[30];
     4 int lena,lenb;
     5 int LCS(int,int);  ///两个参数分别表示数组a的下标和数组b的下标
     6 
     7 int main()
     8 {
     9     strcpy(a,"ABCBDAB");
    10     strcpy(b,"BDCABA");
    11     lena=strlen(a);
    12     lenb=strlen(b);
    13     printf("%d
    ",LCS(0,0));
    14     return 0;
    15 }
    16 
    17 int LCS(int i,int j)
    18 {
    19     if(i>=lena || j>=lenb)
    20         return 0;
    21     if(a[i]==b[j])
    22         return 1+LCS(i+1,j+1);
    23     else
    24         return LCS(i+1,j)>LCS(i,j+1)? LCS(i+1,j):LCS(i,j+1);
    25 }

    用递归的方法优点是编程简单,容易理解。缺点是效率不高,有大量的重复执行递归调用,而且只能求出最大公共子序列的长度,求不出具体的最大公共子序列。

      (2)动态规划求最长公共子序列的长度

        动态规划采用二维数组来标识中间计算结果,避免重复的计算来提高效率。

        1)最长公共子序列的长度的动态规划方程

        设有字符串a[0...n],b[0...m],下面就是递推公式。字符串a对应的是二维数组num的行,字符串b对应的是二维数组num的列。

        

    代码如下:

     1 #include<stdio.h>
     2 #include<string.h>
     3 
     4 char a[500],b[500];
     5 char num[501][501]; ///记录中间结果的数组
     6 char flag[501][501];    ///标记数组,用于标识下标的走向,构造出公共子序列
     7 void LCS(); ///动态规划求解
     8 void getLCS();    ///采用倒推方式求最长公共子序列
     9 
    10 int main()
    11 {
    12     int i;
    13     strcpy(a,"ABCBDAB");
    14     strcpy(b,"BDCABA");
    15     memset(num,0,sizeof(num));
    16     memset(flag,0,sizeof(flag));
    17     LCS();
    18     printf("%d
    ",num[strlen(a)][strlen(b)]);
    19     getLCS();
    20     return 0;
    21 }
    22 
    23 void LCS()
    24 {
    25     int i,j;
    26     for(i=1;i<=strlen(a);i++)
    27     {
    28         for(j=1;j<=strlen(b);j++)
    29         {
    30             if(a[i-1]==b[j-1])   ///注意这里的下标是i-1与j-1
    31             {
    32                 num[i][j]=num[i-1][j-1]+1;
    33                 flag[i][j]=1;  ///斜向下标记
    34             }
    35             else if(num[i][j-1]>num[i-1][j])
    36             {
    37                 num[i][j]=num[i][j-1];
    38                 flag[i][j]=2;  ///向右标记
    39             }
    40             else
    41             {
    42                 num[i][j]=num[i-1][j];
    43                 flag[i][j]=3;  ///向下标记
    44             }
    45         }
    46     }
    47 }
    48 
    49 void getLCS()
    50 {
    51 
    52     char res[500];
    53     int i=strlen(a);
    54     int j=strlen(b);
    55     int k=0;    ///用于保存结果的数组标志位
    56     while(i>0 && j>0)
    57     {
    58         if(flag[i][j]==1)   ///如果是斜向下标记
    59         {
    60             res[k]=a[i-1];
    61             k++;
    62             i--;
    63             j--;
    64         }
    65         else if(flag[i][j]==2)  ///如果是斜向右标记
    66             j--;
    67         else if(flag[i][j]==3)  ///如果是斜向下标记
    68             i--;
    69     }
    70 
    71     for(i=k-1;i>=0;i--)
    72         printf("%c",res[i]);
    73 }

    (3)图示

    最长公共子串

     1 import java.util.Scanner;
     2 
     3 public class Main {
     4     public static void main(String[] args) {
     5         Scanner sc = new Scanner(System.in);
     6         Main mainObj = new Main();
     7         int len = mainObj.getCommonStrLength(sc.next(),sc.next());
     8         System.out.println(len);
     9     }
    10     
    11     int getCommonStrLength(String str1, String str2) {
    12              str1 = str1.toLowerCase();  
    13             str2 = str2.toLowerCase();  
    14             int len1 = str1.length();  
    15             int len2 = str2.length();  
    16             String min = null;  
    17             String max = null;  
    18             String target = null;
    19             min = len1 <= len2 ? str1 : str2;
    20             max = len1 >  len2 ? str1 : str2;
    21             //最外层:min子串的长度,从最大长度开始
    22             for (int i = min.length(); i >= 1; i--) {
    23                 //遍历长度为i的min子串,从0开始
    24                 for (int j = 0; j <= min.length() - i; j++) {  
    25                     target = min.substring(j, j + i);  
    26                     //遍历长度为i的max子串,判断是否与target子串相同,从0开始
    27                     for (int k = 0; k <= max.length() - i; k++) {  
    28                         if (max.substring(k,k + i).equals(target)) {  
    29                             return i;  
    30                         }
    31                     }
    32                 }
    33             }  
    34             return 0;  
    35     }
    36 }
    Jumping from failure to failure with undiminished enthusiasm is the big secret to success.
  • 相关阅读:
    最长公共子串
    Windows 下GitHub 安装和使用
    JSON 解析
    利用bootsrap控件 实现文件上传功能
    CCF 工资计算
    Java 对象引用以及对象赋值
    Java 关于创建String对象过程的内存分配
    JAVA堆内存和栈内存初步了解
    URAL 1152. False Mirrors (记忆化搜索 状压DP)
    POJ 1113 Wall(Graham求凸包周长)
  • 原文地址:https://www.cnblogs.com/chongerlishan/p/5970287.html
Copyright © 2011-2022 走看看