最长公共子序列-空间优化-BITOJ

<空间优化>

求两个字符串的最长公共子序列的长度。

输入:

第一行字符串 S1 
第二行字符串 S2 
(注:字符为英文字母,大小写均可。字符串长度大于等于1 ,各不大于10000)

输出:
数字 M ,为最长公共子序列长度。

例如:

输入:

BDCABA
ABCBDAB
输出:

4

 

 测试输入帮助,input (新窗口)期待的输出帮助,expectedoutput (新窗口)时间限制帮助,timelimit (新窗口)内存限制帮助,memlimit (新窗口)额外进程帮助,nproc (新窗口)
测试用例 1 以文本方式显示
  1. ABKLMNABCDI↵
  2. ABCDEFGHIJKLMNOPQRSTUVWXYZ↵
以文本方式显示
  1. 6↵
1秒 256KB 0

思路:典型的动态规划问题

dp[i][j]:表示a串前i个字符与b串前j个字符的最长公共字符的个数,dp[n][m]即为最后的结果。

显然:

dp[i][j]=dp[i-1][j-1]+1; if(a[i]==b[j])
dp[i][j]=max(dp[i-1][j],dp[i][j-1]); if(a[i]!=b[j])

于是可以递推下去,求解dp[n][m]。

这里提出一点小小的空间优化:

递推的时候,我们需要求解dp[i][j],因此需要用到dp[i-1][j-1],dp[i-1][j],dp[i][j-1];这三个状态。

可以看出不需要dp[i-2],dp[i-3]...等状态,于是这里可以有空间优化。

最典型的奇偶优化,因为只需要存储dp[i],dp[i-1]这两个相邻的状态,i,i-1,二者必须是一个奇数一个偶数,所以奇偶优化就显得很方便。

奇偶递推式:

dp[i&1][j]=dp[(i-1)&1][j-1]+1;if(a[i]==b[j])
dp[i&1][j]=max2(dp[(i-1)&1][j],dp[i&1][j-1]);if(a[i]!=b[j])

这样dp数组可以优化到:2*m,m为字符串中长度最短的那个。

View Code
 1 #include<stdlib.h>
2 #include<string.h>
3 #include<stdio.h>
4 #define max2(a,b) (a>b)?a:b
5 #define N 10001
6
7 char str[2][N];
8 int dp[2][N];
9 int main()
10 {
11 int i,j,k,n,m;
12 while(~scanf("%s%s",str[0],str[1]))
13 {
14 n=strlen(str[0]);
15 m=strlen(str[1]);
16 memset(dp,0,sizeof(dp));
17 for(i=1;i<=n;i++)
18 for(j=1;j<=m;j++)
19 if(str[0][i-1] == str[1][j-1])
20 dp[i&1][j]=dp[(i-1)&1][j-1]+1;
21 else
22 dp[i&1][j]=max2(dp[(i-1)&1][j],dp[i&1][j-1]);
23 printf("%d\n",dp[n&1][m]);
24 }
25 return 0;
26 }



posted on 2012-03-16 13:23  kevinkitty  阅读(1958)  评论(5编辑  收藏  举报

导航