LCS, LIS, 线性空间LCS( hirschberg算法)
2009-11-22 22:20
471 查看
今天帮同学写了三个代码,分别是简单LCS,LIS,以及使用线性空间的LCS。
首先是LCS(longest common substring最长公共子序列),这是动态规划的典型例题,各种算法书里都会讲到的一个问题。个人推荐这个网页http://blog.163.com/hzzy-010/blog/static/79692381200872024242126/ 。 讲的非常清楚,图例也很好,可以把你从不懂讲到懂。由于他讲的实在很详细,我就不好意思再说了。直接上代码了。代码比较搓,将就着看吧。
LIS(longest increasing substring)也是一个动态规划问题,有O(n2)以及O(nlogn)两种解法,我用了比较简单的算法。具体的递推公式是:len(i) = max{str[i] > str[j]? len[i]+1 : 1} 0=< j < i; 然后我们从len的数组中找到最长子串,注意不是说最后一个len一定是最长的。然后输出。代码如下:
线性空间LCS,这是使用线性的空间来解LCS问题,主要为了解决长字符串而由hirschberg发明的。可以看维基上的介绍:http://en.wikipedia.org/wiki/Hirschberg%27s_algorithm,当然也可以找他的论文看看,名字叫:A Linear Space Algorithm for Computing Maximal Common Subsequences 。这个解法使用到了动态规划以及分治算法,在时间复杂度上面有所增加,但是减少了空间复杂度。它首先把a数组一分为二,然后考虑所有的b数组二分的方法,找到一个subsequence最长的方法,然后将两个数组一分为二,分别再次计算。这个算法之所以可以成功,还有一个原因就是下面代码中的LCS_B算法可以使用线性空间获得最长子序列的长度。好了,代码如下:
首先是LCS(longest common substring最长公共子序列),这是动态规划的典型例题,各种算法书里都会讲到的一个问题。个人推荐这个网页http://blog.163.com/hzzy-010/blog/static/79692381200872024242126/ 。 讲的非常清楚,图例也很好,可以把你从不懂讲到懂。由于他讲的实在很详细,我就不好意思再说了。直接上代码了。代码比较搓,将就着看吧。
#include<stdio.h> #include<string.h> #define MAXLEN 100 int max_three(int a,int b,int c,int &back) { int max = a; back = 0; if(max < b) { max = b; back = 1; } if(max < c) { max = c; back = 2; } return max; } int main() { char x[MAXLEN]; char y[MAXLEN]; int matrix[MAXLEN][MAXLEN]; int back[MAXLEN][MAXLEN]; char result[MAXLEN]; printf("input string a/n"); scanf("%s",&x); printf("input string b/n"); scanf("%s",&y); int xlen = strlen(x); int ylen = strlen(y); for(int i=0;i<xlen;i++) { for(int j=0;j<ylen;j++) { matrix[i][j] = 0; } } for(int i=1;i<=xlen;i++) for(int j=1;j<=ylen;j++) { if(i*j!=0) { if(x[i-1] == y[j-1]) { matrix[i][j] = max_three(matrix[i-1][j-1]+1, matrix[i][j-1],matrix[i-1][j], back[i][j]); }else { matrix[i][j] = max_three(matrix[i-1][j-1], matrix[i][j-1],matrix[i-1][j], back[i][j]); } } } printf("the LCS length is %d/n",matrix[xlen][ylen]); int xx = xlen; int yy = ylen; char ans[MAXLEN]; int ansl=0; while(true) { if(back[xx][yy] == 0&& x[xx-1] == y[yy-1]) { ans[ansl++] = x[xx-1]; } if(back[xx][yy] == 0) { xx--; yy--; } else if(back[xx][yy] == 1) { yy--; }else xx--; if(xx == 0&&yy == 0) break; } printf("the LCS is:/n"); for(int i=matrix[xlen][ylen]-1;i>=0;i--) printf("%c",ans[i]); printf("/n"); }
LIS(longest increasing substring)也是一个动态规划问题,有O(n2)以及O(nlogn)两种解法,我用了比较简单的算法。具体的递推公式是:len(i) = max{str[i] > str[j]? len[i]+1 : 1} 0=< j < i; 然后我们从len的数组中找到最长子串,注意不是说最后一个len一定是最长的。然后输出。代码如下:
#include<stdio.h> #include<string.h> #define MAXLEN 100 int main() { char x[MAXLEN]; int l[MAXLEN]; int pro[MAXLEN]; for(i=0;i<MAXLEN;i++) { l[i] = 1; pro[i] = -1; } printf("input the string:/n"); scanf("%s",&x); l[0] = 1; pro[0] = -1; int len = strlen(x); for(int i=1;i<len;i++) { int max = 0; pro[i] = -1; for(int j=0;j<i;j++) { l[i] = x[i] > x[j]?l[j]+1:1; if(max <l[i]) { max = l[i]; pro[i] = j; } } l[i] = max; } int lis = l[len-1]; int sub = len-1; for(int i=len-2;i>=0;i--) { if(lis <l[i]) { lis = l[i]; sub = i; } } printf("the length of LIS is:%d/n",lis); char ans[MAXLEN]; int ansl=0; int i = sub; while(pro[i]!=-1) { ans[ansl++] = x[i]; i = pro[i]; } printf("the LIS is:/n%c",x[i]); for(int i=ansl-1;i>=0;i--) { printf("%c",ans[i]); } printf("/n"); }
线性空间LCS,这是使用线性的空间来解LCS问题,主要为了解决长字符串而由hirschberg发明的。可以看维基上的介绍:http://en.wikipedia.org/wiki/Hirschberg%27s_algorithm,当然也可以找他的论文看看,名字叫:A Linear Space Algorithm for Computing Maximal Common Subsequences 。这个解法使用到了动态规划以及分治算法,在时间复杂度上面有所增加,但是减少了空间复杂度。它首先把a数组一分为二,然后考虑所有的b数组二分的方法,找到一个subsequence最长的方法,然后将两个数组一分为二,分别再次计算。这个算法之所以可以成功,还有一个原因就是下面代码中的LCS_B算法可以使用线性空间获得最长子序列的长度。好了,代码如下:
#include<stdio.h> #include<string.h> #define MAXLEN 100 void reverstring(char* x,char* xr) { int len = strlen(x); for(int i=0;i<len;i++) { xr[i] = x[len-i-1]; } xr[len] = '/0'; } int max(int a,int b) { return a>b?a:b; } void LCS_B(int m, int n, char* A, char* B, int& L) { int K[2][MAXLEN]; for(int j=0;j<=n;j++) K[1][j] = 0; for(int i=1;i<=m;i++) { for(int j=0;j<=n;j++) K[0][j] = K[1][j]; for(int j=1;j<=n;j++) { if(A[i-1] == B[j-1]) { K[1][j] = K[0][j-1]+1; } else K[1][j] = max(K[1][j-1],K[0][j]); } } L = K[1] ; } void LCS_A(int m,int n,char* x, char* y, char* res) { char xr[MAXLEN]; char yr[MAXLEN]; x[m] = '/0'; y = '/0'; reverstring(x, xr); reverstring(y, yr); if(n==0) { strcpy(res,""); return; } if(m==1) { for(int i=0;i<n;i++) { if(x[0] == y[i]) { res[0] = x[0]; res[1] = '/0'; break; } } return; } int i = m/2; int maxsum = -1; int k = -1; for(int j=0;j<=n;j++) { int L1,L2; L1 = L2 = 0; LCS_B(i,j,x,y,L1); LCS_B(m-i,n-j,xr,yr,L2); if(maxsum < L1+L2) { maxsum = L1+L2; k = j; } } char c1[MAXLEN]; char c2[MAXLEN]; char xx[MAXLEN]; char yy[MAXLEN]; int xsub = 0; int ysub = 0; for(int j=i;j<=m;j++) { xx[xsub++] = x[j]; } for(int j=k;j<=n;j++) { yy[ysub++] = y[j]; } LCS_A(i,k,x,y,c1); LCS_A(m-i,n-k,xx ,yy ,c2); strcat(c1,c2); strcpy(res,c1); } int main() { char x[MAXLEN]; char y[MAXLEN]; char res[MAXLEN]; printf("input string a:/n"); scanf("%s",&x); printf("input string b:/n"); scanf("%s",&y); LCS_A(strlen(x),strlen(y),x,y,res); printf("the length is: %d/n",strlen(res)); printf("the LCS is:/n%s/n",res); }
相关文章推荐
- LIS&LCS 线性结构dp
- 线性DP总结(LIS,LCS,LCIS,最长子段和)
- 线性DP总结(LIS,LCS,LCIS,最长子段和)
- 向量空间 内积空间 线性空间 欧氏空间 希尔伯特空间
- UVa 10635 - Prince and Princess(LCS转LIS)
- NYOJ 17(LIS转为LCS,但是MLE)
- LCS?LIS
- Linux内存线性地址空间布局解析
- uva 10635 Prince and Princess (将LCS 转化为 LIS)
- uva 10635Prince and Princess (LCS转LIS)
- 线性代数 -- 矩阵空间、秩1矩阵、小世界图
- (UVA - 10635)Prince and Princess (LCS变形为LIS,DP)
- UVA - 10635 Prince and Princess LCS转LIS
- android ui 布局<线性布局中的剩余空间使用>
- UVA 10635 - Prince and Princess ( LCS 转换为LIS )
- 白话空间统计十一:线性方向平均值
- 线性空间求最长公共子序列的Nakatsu算法
- 有限维实线性空间上的无界的闭凸集必有方向
- 线性空间的概念
- 向量间的距离和范数到线性空间、赋范空间、內积空间