大白话讲解LCS(最长公共子序列)
2018-04-03 16:53
405 查看
今天看了七月在线算法课。再一次认识了LCS,现在整理记录:
LCS(Longest Common Subsequence)最长公共子序列。
一个序列S任意删除若干个字符得到新序列T,那么T叫做S的子序列。
两个序列X和Y的公共子序列中,长度最长的那个叫X和Y的最长公共子序列。
例如:
字符串13455和245576的最长公共子序列为455.
字符串acdfg和adfc的最长公共子序列为adf.
注意:这里要区别最长公共子串LCS(Longest Common Substring),这个要求的是字符串必须连续。
这里偷懒,直接拿了老师的PPT。记好下面的记号。
下面就进行LCS解法的探索:
当x=y的时候:
然后我们就能得到:
此处的意思就是:当两个子序列中结尾字符是相等的,那么最长的子序列就肯定是这个相等值+前面的的最长长度了,这样他们的长度才能是最长的。
例子:
那么现在我们再考虑X不等于Y的情况:
此处的解释:
当我们认为是我们子序列的子串的最后一个元素不相等,那么他的最长子序列一定来自两个地方,假设去掉X序列的最后一个元素,那么最长子序列一定产生于图中A+B+Yn,同理一样, B+A+Xn.
例子:
总结:
怎么求呢?C[m,n]是一个正整数的值,表示序列m和n之间的最大的长度。
当两个字符串有一个是0 ,那么LCS一定是0;
例子:
右下角的数据怎么计算呢?
经过上面的分析,我们知道两个序列有一个是0 的那么LCS都是0 ;所以第0行第0列都是0.
图中红圈内1怎么得来的呢?
红圈内的x是B,y是D,即x不等于y.那么我们就要看红圈上左边和上边 的数值了,选择一个大的数值写入。
那么以此类推,当x=y 的时候,我们直接选择红圈左上的值+1,写入即可。
两个例子来自点击打开链接
代码一是让你输入两个序列,然后输出最长公共子序列和长度。
LCS(Longest Common Subsequence)最长公共子序列。
一个序列S任意删除若干个字符得到新序列T,那么T叫做S的子序列。
两个序列X和Y的公共子序列中,长度最长的那个叫X和Y的最长公共子序列。
例如:
字符串13455和245576的最长公共子序列为455.
字符串acdfg和adfc的最长公共子序列为adf.
注意:这里要区别最长公共子串LCS(Longest Common Substring),这个要求的是字符串必须连续。
这里偷懒,直接拿了老师的PPT。记好下面的记号。
下面就进行LCS解法的探索:
当x=y的时候:
然后我们就能得到:
此处的意思就是:当两个子序列中结尾字符是相等的,那么最长的子序列就肯定是这个相等值+前面的的最长长度了,这样他们的长度才能是最长的。
例子:
那么现在我们再考虑X不等于Y的情况:
此处的解释:
当我们认为是我们子序列的子串的最后一个元素不相等,那么他的最长子序列一定来自两个地方,假设去掉X序列的最后一个元素,那么最长子序列一定产生于图中A+B+Yn,同理一样, B+A+Xn.
例子:
总结:
怎么求呢?C[m,n]是一个正整数的值,表示序列m和n之间的最大的长度。
当两个字符串有一个是0 ,那么LCS一定是0;
例子:
右下角的数据怎么计算呢?
经过上面的分析,我们知道两个序列有一个是0 的那么LCS都是0 ;所以第0行第0列都是0.
图中红圈内1怎么得来的呢?
红圈内的x是B,y是D,即x不等于y.那么我们就要看红圈上左边和上边 的数值了,选择一个大的数值写入。
那么以此类推,当x=y 的时候,我们直接选择红圈左上的值+1,写入即可。
两个例子来自点击打开链接
代码一是让你输入两个序列,然后输出最长公共子序列和长度。
#include <stdio.h> #include <string.h> #include <stdlib.h> int LCSLength(char* str1, char* str2, int **b) { int i,j,length1,length2,len; length1 = strlen(str1); length2 = strlen(str2); //双指针的方法申请动态二维数组 int **c = new int*[length1+1]; //共有length1+1行 for(i = 0; i < length1+1; i++) c[i] = new int[length2+1];//共有length2+1列 for(i = 0; i < length1+1; i++) c[i][0]=0; //第0列都初始化为0 for(j = 0; j < length2+1; j++) c[0][j]=0; //第0行都初始化为0 for(i = 1; i < length1+1; i++) { for(j = 1; j < length2+1; j++) { if(str1[i-1]==str2[j-1])//由于c[][]的0行0列没有使用,c[][]的第i行元素对应str1的第i-1个元素 { c[i][j]=c[i-1][j-1]+1; b[i][j]=0; //输出公共子串时的搜索方向 } else if(c[i-1][j]>c[i][j-1]) { c[i][j]=c[i-1][j]; b[i][j]=1; } else { c[i][j]=c[i][j-1]; b[i][j]=-1; } } } /* for(i= 0; i < length1+1; i++) { for(j = 0; j < length2+1; j++) printf("%d ",c[i][j]); printf("\n"); } */ len=c[length1][length2]; for(i = 0; i < length1+1; i++) //释放动态申请的二维数组 delete[] c[i]; delete[] c; return len; } void PrintLCS(int **b, char *str1, int i, int j) { if(i==0 || j==0) return ; if(b[i][j]==0) { PrintLCS(b, str1, i-1, j-1);//从后面开始递归,所以要先递归到子串的前面,然后从前往后开始输出子串 printf("%c",str1[i-1]);//c[][]的第i行元素对应str1的第i-1个元素 } else if(b[i][j]==1) PrintLCS(b, str1, i-1, j); else PrintLCS(b, str1, i, j-1); } int main(void) { char str1[100],str2[100]; int i,length1,length2,len; printf("请输入第一个字符串:"); gets(str1); printf("请输入第二个字符串:"); gets(str2); length1 = strlen(str1); length2 = strlen(str2); //双指针的方法申请动态二维数组 int **b = new int*[length1+1]; for(i= 0; i < length1+1; i++) b[i] = new int[length2+1]; len=LCSLength(str1,str2,b); printf("最长公共子序列的长度为:%d\n",len); printf("最长公共子序列为:"); PrintLCS(b,str1,length1,length2); printf("\n"); for(i = 0; i < length1+1; i++)//释放动态申请的二维数组 delete[] b[i]; delete[] b; system("pause"); return 0; }
相关文章推荐
- Android Studio 的 Gradle大白话讲解
- LCS,最长公共子序列
- 第11章:最长公共子序列(LCS:Longest Common Subsequence)
- nyoj 最长公共子序列 36 (简单LCS模板)
- 最长公共子序列(LCS)问题
- Common Subsequence(LCS最长公共子序列)
- 动态规划实现最长公共子序列(LCS)算法
- 【51Nod】1006 - 最长公共子序列Lcs(LCS)
- 最长公共子序列问题——LCS
- BZOJ 3304: [Shoi2005]带限制的最长公共子序列( LCS )
- 【经典问题】二维动态规划问题:求最长公共子序列LCS
- 最长公共子序列(LCS)
- 最长公共子序列(LCS)
- 动态规划解最长公共子序列问题LCS(longest common subsequence)
- 51Nod 1006 - 最长公共子序列(Lcs)
- poj1458--Common Subsequence--最长公共子序列LCS
- 最长公共子序列Lcs
- 最长公共子序列(LCS)的两种求解方法
- 大白话讲解Promise
- 最长公共子序列LCS问题