hdu 1159 dp(最长公共子序列)
在这附一个别人的网址,是求LCS时的空间优化
http://blog.sina.com.cn/s/blog_7826c4dd01011em0.html
我贴两个代码,空间复杂度分别为 O(2*n)的和O(n)的
空间复杂度O(2*n)
//hdu 1159 dp(最长公共子序列) //以下是空间复杂度为O(2*n)的代码 #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 3000 char tmp1[N], tmp2[N]; //这里本来应该是 dp[N][N]的,应为求LCS时,用第一串的 //第i 个字符与第二串匹配时,时从前一个字符跟第二串每个字符匹配 //得到的最优值转移过来的,具体看下面代码和注释 int dp[2][N]; int LCSL(char *t1, char *t2) { memset(dp, 0, sizeof(dp)); int len1= strlen(t1), len2 = strlen(t2); //求LCSL时就是 for(int i = 0; i < len1; ++i) { //第一串 的 i字符和第二串的 j字符匹配时 for(int j = 0; j < len2; ++j) { //若匹配成功,则dp[i][j] = dp[i-1][j-1]+1,意思是从 //t1的 前 i-1个字符和t2串的 前 j-1个字符匹配中最优值+1 if(t1[i] == t2[j]) //这里本可以(i-1)&1 可是i从0开始所以(i+1)&1也一样 dp[i&1][j] = dp[ (i+1)&1 ][j-1] + 1; else //若匹配不成功,则取 t1第i个 和t2第j-1个匹配时的最优值或i-1 和 j匹配 dp[i&1][j] = max(dp[i&1][j-1], dp[ (i+1)&1 ][j]);//时的最优值 中的最大值 } //在求c(i,j)时,只用到了c(i-1,j)和c(i,j-1),所以可以用滚动数组来优化 } return dp[(len1-1)&1][len2-1]; } int main() { while(scanf("%s%s", tmp1, tmp2) != EOF) { printf("%d\n", LCSL(tmp1, tmp2)); } return 0; }
空间复杂度O(n)
//hdu 1159 dp(最长公共子序列) //以下是空间复杂度为O(n)的代码 #include <stdio.h> #include <string.h> #define N 3005 int n; char tmp1[N], tmp2[N]; //这里本来应该是 dp[N][N]的,应为求LCSL时,用第一串的 //第i 个字符与第二串匹配时,时从前一个字符跟第二串每个字符匹配 //得到的最优值转移过来的,具体看下面代码和注释 int dp[N]; int max(int a, int b) { return a > b ? a : b; } int LCSL(char *t1, char *t2) { int m, len1 = strlen(t1), len2 = strlen(t2); memset(dp, 0, sizeof(dp)); //求LCS时就是 for(int i = len1-1; i >= 0; --i) { //第一串 的 i字符和第二串的 j字符匹配时 int tmp = 0; //tmp记录对角线的值,即从前往后推的dp[i-1][j-1] for(int j = len2-1; j >= 0; --j) { m = max(dp[j], dp[j+1]); if(t1[i] == t2[j]) { m = max(tmp+1, m); } tmp = dp[j]; //继续取对角线的值 dp[j] = m; //覆盖当前值 } } return dp[0]; } int main() { while(scanf("%s%s", tmp1, tmp2) != EOF) { printf("%d\n", LCSL(tmp1, tmp2)); } return 0; }