最长公共子串/子序列

来源:互联网 发布:霍先生家的安之知 编辑:程序博客网 时间:2024/04/27 15:48

最长公共子串:找两个字符串的最长公共子串,要求在原字符串中是连续的

最长公共子序列:不要求连续

最长公共子串思路:

声明一个二维数组dp[][]来存放相对应的最长公共子串数

            arr1[m]=arr2[n]时,dp[m+1][n+1]=1+dp[m][n]  即当子序列中第 m+1 元素与目标序列中第 n+1 元素相同时,子序列前 m+1 个元素与目标序列前 n+1 个元素的最长公共子串数为子序列前 m 个元素与目标序列前 n 个元素的最长公共子串数 + 1;

            arr1[m] != arr2[n]时,dp[m+1][n+1]=0;即当子序列中第 m+1 元素与目标序列中第 n+1 元素不相同时,子序列前 m+1 个元素与目标序列前 n+1 个元素的最长公共子串长为0 ;第二步:找出最大值,依次输出其左上角


#include<stdio.h>int weight[101];//子串权值char substr[101];//子串字母char sbustrs[100][100];//int maxlcs=0;//LCS大小int a=0;char arr1[]="bab";char arr2[]="caba";int dp[101][101]={0};//dp[i][j]存放字串前i-1,目标串前j-1个元素的LCS,初始全为0int LCS(char *arr1,int size1 ,char *arr2,int size2 )//求出dp[][];{for(int i=0 ;i < size1; i++ )//依次增加子序列长度{for(int j=0 ;j< size2; j++)//依次增加目标序列长度{if(arr1[i]==arr2[j]){dp[j+1][i+1]=dp[j][i]+1;//当前匹配相同,对应LCS等于前一LCS+1if(maxlcs<dp[j+1][i+1])maxlcs= dp[j+1][i+1];//找到LCS的最大值}else dp[j+1][i+1]=0;//当前匹配不同,对应LCS等于左侧和上侧LCS中的较大值}}return 0;}int Find ( int n ,int m ,int nextmax )//找出所有匹配点,记录相应字符和权值{ int k, j;if (nextmax==0){ printf("\n");return 0;}for(k=m+n ; k>0 ;k--){for( j=n ; j>0 && (k-j)<(m+1) ; j--){if(dp[k-j][j]==nextmax){        printf("%d %d %d",k-j,j,nextmax);printf("%c   ",arr1[j-1]);if (nextmax==0) printf("\n");Find(j-1,k-j-1,nextmax-1);//递归查找下一层级}}}return 0;}int main(){LCS(arr1,3,arr2,4);Find(3,4,maxlcs);return 0;}


   

最长公共子序列思路:

第一步:声明一个二维数组dp[][]来存放相对应的最长公共子序列数

              arr1[m]=arr2[n]时,dp[m+1][n+1]=1+dp[m][n]  即当子序列中第 m+1 元素与目标序列中第 n+1 元素相同时,子序列前 m+1 个元素与目标序列前 n+1 个元素的最长公共子序列数为子序列前 m 个元素与目标序列前 n 个元素的最长公共子序列数 + 1;

              arr1[m] != arr2[n]时,dp[m+1][n+1]=max{dp[m][n+1],dp[m+1][n]} 即当子序列中第 m+1 元素与目标序列中第 n+1 元素不相同时,子序列前 m+1 个元素与目标序列前 n+1 个元素的最长公共子序列数为子序列前 m 个元素与目标序列前 n+1 个元素的最长公共子序列数 和 子序列前 m+1 个元素与目标序列前 n 个元素的最长公共子序列数中的较大值 ;

第二步:递归找出每一个匹配点对应的子序列,递归输出

  1 #include<stdio.h>  2 char substr[101];//子串字母  3 int maxlcs=0;//LCS大小  4 char arr1[]="DADFDAB";  5 char arr2[]="ABDEFAFCD";  6 int dp[101][101]={0};//dp[i][j]存放字串前i-1,目标串前j-1个元素的LCS,初始全为0  7 int LCS(char *arr1,int size1 ,char *arr2,int size2 )//求出dp[][];  8 {  9         for(int i=0 ;i < size1; i++ )//依次增加子序列长度 10         { 11                 for(int j=0 ;j< size2; j++)//依次增加目标序列长度 12                 { 13                         if(arr1[i]==arr2[j]) dp[j+1][i+1]=dp[j][i]+1;//当前匹配相同,对应LCS等于前一LCS+1 14                         else dp[j+1][i+1]=(dp[j+1][i]>dp[j][i+1]?dp[j+1][i]:dp[j][i+1]);//当前匹配不同,对应LCS等于左侧和上侧LCS中的较大值 15                 } 16         } 17         maxlcs= dp[size2][size1];//找到LCS的最大值 18         return 0; 19 } 20 int Find ( int n ,int m ,int nextmax )//找出所有匹配点,记录相应字符和权值 21 { 22         int k, j; 23         if (nextmax==0){ printf("%s \n",substr);return 0;}//当找到首个元素后输出记录 24         for(k=m+n ; k>0 ;k--) 25         { 26                 for( j=n ; j>0 && (k-j)<(m+1) ; j--) 27                 { 28                         if((dp[k-j][j]==nextmax) && (arr1[j-1]==arr2[k-j-1]))//权值为当前最大,且对应字母匹配则记录 29                         { 30                                 substr[maxlcs-nextmax]=arr1[j-1];//将记录存入数组与递归层数相对应位置,新分支覆盖原有分支,保留共用部分 31                                 Find(j-1,k-j-1,nextmax-1);//递归查找下一层级 32                         } 33                 } 34         } 35         return 0; 36 } 37 int main() 38 { 39         LCS(arr1,7,arr2,9); 40         Find(7,9,maxlcs); 41         return 0; 42 }





0 0