动态规划基础——最长公共子序列
问题:求两字符串的最长公共子序列。
当然,要注意的是并没要求连续,连续的话就是子串了。
如:s1 = "abc"; s2 = "adc";
substring = "ac";
解这题的思想,就是运用已知结果来计算未知。
在对字符是否相等进行判断时,需要记下当前公共子序列长度,为以后判断使用:
如开始判断s1[i] 与 s2[j]是否相等:
当两个字符相等时,显然,当前子序列长度 c[i][j] = c[i-1][j-1] +1
当两个字符不相等时,s1[i]与s2[j]的公共子序列就是 s1[i-1]与s2[j]、s1[i]与s2[j-1]这两对字符串当中公共子序列最长的那一个,并且 c[i][j] 设为此长度。
即 c[i][j] = c[i-1][j-1] +1 (s1[i]==s2[j])
c[i][j] = c[i-1][j] (s1[i]!=s2[j]&&c[i-1][j]>c[i][j-1])
c[i][j] = c[i][j-1] (s1[i]!=s2[j]&&c[i-1][j]<c[i][j-1])
代码如下:
#include<stdio.h> #include<stdlib.h> #include<string> //本函数未返回最长公共子序列,只是求出各个子串的公共子序列 void MaxLength( char* s1, char* s2) { int l1 = strlen(s1); int l2 = strlen(s2); //子串 char ***substring; int **c; //构造数组c[l1][l2],存储各状态下,公共子串长度
//在本函数中*substring[i][j]与c[i][j]均表示s1长度为i的子串与s2长度为j的子串的公共子序列及其长度
c = new int*[l1+1]; for(int i = 0; i <= l1; i++) { c[i] = new int[l2+1]; for(int j =0; j <= l2; j++) c[i][j] = 0; } //为子串分配空间(最长为相应s2子串长度) substring = new char**[l1+1]; for(int i = 0; i <= l1 ; i++) substring[i] = new char*[l2+1]; for(int i = 0; i <= l1; i++) for(int j = 0; j <= l2; j++) { substring[i][j] = new char[j+1]; //if( i == 0 || j == 0) *substring[i][j] = NULL; } for(int i = 0; i < l1; i++) { for(int j = 0; j < l2; j++) { if(s1[i] == s2[j]) { c[i+1][j+1] = c[i][j] + 1; //先将先前结果赋给substring[i+1][j+1] strncat(substring[i+1][j+1],substring[i][j],strlen(substring[i][j])); //增添新字符 strncat(substring[i+1][j+1] ,s1 + i,1); } else if(c[i+1][j]<c[i][j+1]) { c[i+1][j+1] = c[i][j+1]; strcpy(substring[i+1][j+1],substring[i][j+1]); } else { c[i+1][j+1] = c[i+1][j]; strcpy(substring[i+1][j+1], substring[i+1][j]); } } } for(int i = 0; i < l1; i++) { for(int j = 0; j <l2; j++) { printf("s1[%d]与s2[%d]的长度是%d,内容是:%s\n",i+1,j+1,c[i+1][j+1],substring[i+1][j+1]); //delete 释放内存空间(末节点未被释放,可单独写释放函数) delete []substring[i][j]; } delete []substring[i]; delete []c[i]; } delete []substring; delete []c; }
//测试函数 int main() { char *s1="11abac"; char *s2="a11ac"; MaxLength(s1,s2); return 0; }
浙公网安备 33010602011771号