最长公共子序列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.
原文地址:https://www.cnblogs.com/chongerlishan/p/5970287.html