一.求解最长公共子序列(LongestCommon Susequence)
问题描述:字符串的字符的相对顺序一致的最长字串,如 “adaskas“,”qascdccasa“->”adaa”
基本思想:动态规划
If(X[i]=Y[j]) LCS[i,j]=LCS[i-1][j-1];
//如果当前字符相同,则此时最长子序列向前各退一位
Else if(X[i]!=y[j]) LCS=max(LCS[i-1][j],LCS[i][j-1]);
//如果当前字符不同,则此时最长子序列为分别各退一位的最大值
伪代码:
C[]数字只是记录当前最长子序列的长度,B[]则是记录最长子序列寻找的方向
M=length(X);n=length(Y)
For(i=1:m) B[0][i]=0;
For(i=1:n) B[i][0]=0;//一个字符串与长度为0的字符串的公共子序列必为0
For(i=1:m)
For(j=1:n)
If(X[i]==Y[j])
B[i][j]=B[i-1][j-1]; C[i][j]=”1”//1代表左上方,2:左 3:上
Else if(B[i-1][j]>B[i][j-1]) //B[i][j]=max(B[i-1][j],B[i][j-1];
B[i][j]=B[i-1][j]; C[i][j]=”3”
Else B[i][j]=B[i][j-1]; C[i][j]=”2”
此时B矩阵最右下角的数字便是最大公共子序列的之长度
如果要输出该子序列时只需要在C[]矩阵中当按照方向向下寻找,当B[i][j]=’1’时输出即可,
时间复杂度:O(mn);
代码:
#include<iostream> #include<string> #include<algorithm> usingnamespace std; int main(){ char str1[] = "abcde"; char str2[] = "abeefcdeghj"; int data[50][50]; int B[50][50]; int len1 =strlen(str1); int len2 =strlen(str2); //cout << len1 << endl; for (int i = 0; i < 50;i++) data[i][0]= data[0][i] = 0; int maxer; for(int i=1;i<=len1;i++) for (int j = 1; j <=len2; j++) { /* maxer =max(data[i][j-1], data[i-1][j]); if(str1[i - 1] == str2[j - 1]) data[i][j]= maxer + 1; else data[i][j]= maxer; */ if (str1[i - 1] !=str2[j - 1]) if (data[i][j - 1]> data[i - 1][j]) { data[i][j]= data[i][j - 1]; B[i][j]= 2;//1代表左上,2代表左,3代表上, } else { data[i][j]= data[i][j - 1]; B[i][j]= 3;//1代表左上,2代表左,3代表上, } else { data[i][j]= max(data[i - 1][j], data[i][j - 1]) + 1; B[i][j]= 1; } } for (int i = 0; i <=len1; i++) { for (int j = 0; j <=len2; j++) printf("%d ", data[i][j]); printf("\n"); } int i=len1; int j = len2; string result="",s=""; while (i !=0&&j!=0) { if (B[i][j] == 1) { //printf("%c", str1[i - 1]); result.insert(0,s+str1[i-1]); i--; j--; } elseif (B[i][j] == 2) j--; elseif(B[i][j]==3) i--; else; } cout<< result<<endl; return 0; }
如果要求解最长公共子串,只需要在B中寻找最大的数字即最长字串的长度,找到后按照对角线逐个输出知道当前值为0即结束
代码:
#include<iostream> #include<algorithm> usingnamespace std; /* 求最长公共子序列:问题描述:求两个字符串中公共的最长字符串长度,只需保持相对顺序连续,不需要连续 核心代码: if (str1[i - 1] == str2[j - 1]) then data[i][j] = data[i - 1][j - 1] +1; 求最长公共子串(本程序的算法):问题描述:求两个字符串最长的公共连续子串,子串必须是连续的 核心代码: if(str1[i-1]==str2[j-1] then data[i][j] = data[i - 1][j - 1] + 1; else data[i][j] = max(data[i - 1][j], data[i][j- 1]); 必要时也可以记录下最长公共子串的内容,代码中加入以下内容: if(str1[i-1]==str2[j-1] then data[i][j] =data[i - 1][j - 1] + 1; B[i][j]="左上" else if(data[i][j-1]>data[i-1][j]) then data[i][j]=data[i][j-1]; B[i][j]="上" else data[i][j]=data[i-1][j]; B[i][j]="左"; */ int main(){ char str1[] = "abcde"; char str2[] = "abeefcdeghj"; int data[50][50]; int len1 =strlen(str1); int len2 =strlen(str2); //cout << len1 << endl; for (int i = 0; i < 50;i++) data[i][0]= data[0][i] = 0; for(inti=1;i<len1+1;i++) for (int j = 1; j <len2+1; j++) { if (str1[i - 1] ==str2[j - 1]) { data[i][j]= data[i - 1][j - 1] + 1; } else data[i][j]= 0; //data[i][j] = max(data[i - 1][j], data[i][j - 1]); } for (int i = 0; i <len1+1; i++) { for (int j = 0; j<len2+1; j++) cout<< data[i][j] <<" "; cout<< endl; } return 0; }