动态规划 最长公共子序列

来源:互联网 发布:四川省委党校网络教育 编辑:程序博客网 时间:2024/05/16 12:02

PS:蓝桥杯的题目做到算法训练动态规划方面的题目就已经陷入瓶颈了呢,虽然系统的学习过,但是现在已经忘了,慢慢边学边做吧!

题目(原题网址):

最长公共子序列
时间限制:3000 ms | 内存限制:65535 KB
难度:3
描述
咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列。
tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。
输入
第一行给出一个整数N(0< N< 100)表示待测数据组数
接下来每组数据两行,分别为待测的两组字符串。每个字符串长度不大于1000.
输出
每组测试数据输出一个整数,表示最长公共子序列长度。每组结果占一行。
样例输入
2
asdf
adfsd
123abc
abc123abc
样例输出
3
6

首先想的是递归~~代码如下:

#include <iostream>#include <string>using namespace std;int LCS(string s1, string s2){    int m = s1.size();    int n = s2.size();    if (m==0 || n==0)   return 0;    else if(s1[m-1] == s2[n-1]) return LCS(s1.substr(0, m-1), s2.substr(0, n-1))+1;    else if(s1[m-1] != s2[n-1])    {        int lcs1 = LCS(s1, s2.substr(0, n-1));        int lcs2 = LCS(s1.substr(0, m-1), s2);        return (lcs1>lcs2)?lcs1:lcs2;    }}int main(){    int n;    cin >> n;    while(n--)    {        string s1, s2;        cin >> s1 >> s2;        cout << LCS(s1, s2) << endl;    }    return 0;} 

毫无疑问的超时了!毕竟是O(2^n)时间复杂度。不过给的测试样例是可以pass的!思路是:从后往前逐字符比对两个字符串s1,s2。

那么现在就要改进算法了。对,动态规划。。代码如下:

#include <iostream>#include <string>using namespace std;#define MAX 1005int d[MAX][MAX];int LCS(string s1, string s2){    int len1, len2;    len1 = s1.size();    len2 = s2.size();    int i, j;    for (i=0; i<=len1; ++i)    {        d[0][i] = 0;    }    for (j=0; j<=len2; ++j)    {        d[j][0] = 0;    }    for (i=0; i<len1; ++i)    {        for (j=0; j<len2; ++j)        {            if (s1[i] == s2[j])            {                d[j+1][i+1] = d[j][i] + 1;            }            else            {                d[j+1][i+1] = d[j][i+1]>d[j+1][i] ? d[j][i+1] : d[j+1][i];            }        }    }    return d[len2][len1];}int main(){    int n;    cin >> n;    while(n--)    {        string s1, s2;        cin >> s1 >> s2;        cout << LCS(s1, s2) << endl;    }    return 0;} 

如果两个字符串长度分别为n,m的话,那么其时间复杂度为O(n*m)。这里指仅对于一对字符串的LCS长度求解。分析什么的就不多说了,网上多的是。再贴一下代码,是这个oj平台的最优代码:

#include <stdio.h>#include <string.h>char s1[1001], s2[1001];int dp[1001], t, old, tmp;int main(){    scanf("%d", &t);    getchar();    while(t--){        gets(s1);        gets(s2);        memset(dp, 0, sizeof(dp));        int lenS1=strlen(s1), lenS2=strlen(s2);        for(int i=0; i<lenS1; i++){            old=0;            //若s1[i]==s2[j], dp[i][j] = dp[i-1][j-1]+1            //否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1])            //此处进行了空间优化,old 代表 dp[i-1][j-1]            //dp[j-1] 代表 dp[i][j-1], dp[j] 代表 dp[i-1][j]            for(int j=0; j<lenS2; j++){                tmp = dp[j];                if(s1[i]==s2[j])                    dp[j] = old+1;                else                    if(dp[j-1]>dp[j])dp[j]=dp[j-1];                old = tmp;            }        }        printf("%d\n";, dp[lenS2-1]);    }    return 0;}

它这里基本思路是一致的,动态规划,不一样的是它又进行了大大的优化,对比如下:
对比
当然,运行时间长的,占用内存多的是我的代码(┬_┬)。

ok,就到这里了。睡觉去~~希望动态规划的学习进度能推快点!

0 0
原创粉丝点击