LCS——例题

LCS

题目描述:

给定一个字符串 s s s 和一个字符串 t t t ,输出 s s s t t t 的最长公共子序列。

输入格式:

两行,第一行输入 s s s ,第二行输入 t t t

输出格式:

输出 s s s t t t 的最长公共子序列。如果有多种答案,输出任何一个都可以。

说明/提示:

数据保证 s s s t t t 仅含英文小写字母,并且 s s s t t t 的长度小于等于3000。

样例 #1

样例输入 #1

axyb
abyxb

样例输出 #1

axb

样例 #2

样例输入 #2

aa
xayaz

样例输出 #2

aa

样例 #3

样例输入 #3

a
z

样例输出 #3


样例 #4

样例输入 #4

abracadabra
avadakedavra

样例输出 #4

aaadara

思路

看到这道题目题干狂喜,我对着题目嘿嘿嘿,看到这个数据范围,题目对着我嘿嘿嘿……

我想着,要不暴力先试试,说不定就过了呢?

这道题主要考察动态规划,写出转移方程即可:

我们虚拟两个分别指向字符串最前面的指针,然后逐一往后去比较

s 1 s1 s1字符串的长度记为 ∣ s 1 ∣ |s1| s1

$ 当s1[i]=s2[j]时,ret[i][j]=ret[i-1][j-1]+s1[i-1] $

当 s 1 [ i ] = s 2 [ j ] 时 : 当s1[i]=s2[j]时: s1[i]=s2[j]:

如 果 ∣ r e t [ i − 1 ] [ j ] ∣ > ∣ r e t [ i ] [ j − 1 ] ∣ , r e t [ i ] [ j ] = r e t [ i − 1 ] [ j ] ; 如果|ret[i-1][j]|>|ret[i][j-1]|,ret[i][j]=ret[i-1][j]; ret[i1][j]>ret[i][j1],ret[i][j]=ret[i1][j];

如 果 ∣ r e t [ i − 1 ] [ j ] ∣ < = ∣ r e t [ i ] [ j − 1 ] ∣ , r e t [ i ] [ j ] = r e t [ i ] [ j − 1 ] ; 如果|ret[i-1][j]|<=|ret[i][j-1]|,ret[i][j]=ret[i][j-1]; ret[i1][j]<=ret[i][j1],ret[i][j]=ret[i][j1];

当我定义了一个$ 3005 *3005 $的string数组的时候,直接段错误(╥﹏╥)

就想着能不能从数组的大小那里优化.

然后我看向了滚动数组~~(滚动数组:不要啊……~~

感觉肯定能过了,然后超时(啪~)

分析思路后,感觉没有问题,后来发现自己的代码实现还可以优化,之前的部分如下:

string Max(string s1,string s2)
{
    return s1.size()>s2.size()?s1:s2;
}

以及

for(int i=1;i<=s1.size();i++){
        for(int j=1;j<=s2.size();j++){
            if(s1[i-1]==s2[j-1]){
                ret[i&1][j]=ret[(i-1)&1][j-1]+s1[i-1];
            }else {
            ret[i&1][j]=Max(ret[(i-1)&1][j],ret[i&1][j-1]);
            }
        }
    }

虽然说封装是个好习惯,但是恰恰是封装成函数,使得这次翻车了……

我掐指一算,发现最坏的情况,调用函数太多导致时间效率过差.

于是我又改进了一下,得到了一下的AC代码.


代码实现

#include<bits/stdc++.h>
using namespace std;
const int maxn=3005;
string Max(string s1,string s2)
{
    return s1.size()>s2.size()?s1:s2;
}
int main()  
{
    string s1,s2;
    string ret[2][maxn]={};
    cin>>s1>>s2;
    for(int i=1;i<=s1.size();i++){
        for(int j=1;j<=s2.size();j++){
            if(s1[i-1]==s2[j-1]){
                ret[i&1][j]=ret[(i-1)&1][j-1]+s1[i-1];
            }else {
            ret[i&1][j]=(ret[(i-1)&1][j].size()>ret[i&1][j-1].size()?ret[(i-1)&1][j]:ret[i&1][j-1]);
            }
        }
    }
    cout<<Max(ret[0][s2.size()],ret[1][s2.size()])<<endl;
    return 0;
}

收获

1、LCS的状态转移方程
2、滚动数组在动态规划的应用
3、自己封装的函数要注意时间的优化,感觉不妙就去掉函数.这条规则同样适用于头文件引用的库函数

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值