2016蓝桥杯C++A组——密码脱落

密码脱落

问题描述

【题目描述】
在这里插入图片描述
【输入】
在这里插入图片描述
【输出】
在这里插入图片描述
【样例输入】

ABCBA
ABDCDCBABC

【样例输出】

0
3

题目解析

二分试探法

对于一个字符串,定义两个指针变量 i , j i,j i,j分别指向字符串的首和尾,当 i i i j j j所指的数值相同时, i + + i++ i++同时 j − − j-- j,如果不相同的话,就需要二分法在左边添加 j j j指向的数或者在右边添加 i i i指向的数,运用递归方法求得最小的步数。

在编程中这种方法很简单就可以实现,但是复杂度在 2 N 2^N 2N数量级,当 N N N 20 20 20时运算量已经很大了所以不能AC全部测试数据。

最长公共子序列的变形

这道题很巧妙的运用了最长公共子序列LCS算法,简单解释一下,对于 A B D C D C B A B C ABDCDCBABC ABDCDCBABC,其逆序字符串是 C B A B C D C D B A CBABCDCDBA CBABCDCDBA,如下图所示比对最长公共子序列,
在这里插入图片描述

我们可以得出二者最长公共子序列是 A B D C D B A ABDCDBA ABDCDBA,还剩3个字符串没有比对上,则 需 要 补 的 数 = l e n − L C S 需要补的数=len-LCS =lenLCS

了解到这个算法后我们的中心就变成如何求解最长公共子序列了。可以用dp算法求解。可以参考我之前的博客最大公共子串

C++代码

二分法代码

#include<bits/stdc++.h>
using namespace std;
char s[1000];
int dfs(char *s,int left,int right,int cnt)
{
    if(left>=right) return cnt;
    if(*(s+left)!=*(s+right)) //两端不相等
        return min(dfs(s,left+1,right,cnt+1),dfs(s,left,right-1,cnt+1));
    else return dfs(s,left+1,right-1,cnt);
}
int main()
{
    scanf("%s",&s);
    int len = strlen(s);
    int ans = dfs(s,0,len-1,0);
    printf("%d\n",ans);
    return 0;
}

LCS代码

#include<bits/stdc++.h>
using namespace std;
char s[1000];
char *rev(char *s)
{
    int len = strlen(s);
    char * ans = (char *)malloc(len*sizeof(char));
    for(int i=0;i<len;i++)
        ans[i] = s[len-i-1];
    return ans;
}
int lcs(const char *s1,const char *s2,int len)
{
    int dp[len][len];
    for(int i=0;i<len;i++) //初始化第一行
    {
        if(s1[i]==s2[0]) dp[0][i]=1;
        else dp[0][i]=(i==0?0:dp[0][i-1]);
    }
    for(int j=0;j<len;j++) //初始化第一列
    {
        if(s2[j]==s1[0]) dp[j][0]=1;
        else dp[j][0]=(j==0?0:dp[j-1][0]);
    }
    for(int i=1;i<len;i++) //构建dp数组
    {
        for(int j=1;j<len;j++)
        {
            if(s2[i]==s1[j]) dp[i][j]=dp[i-1][j-1]+1;
            else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        }
    }
    return dp[len-1][len-1];
}
int main()
{
    scanf("%s",&s);
    int len = strlen(s);
    int l = lcs(s,rev(s),len);
    printf("%d\n",len-l);
    return 0;
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芷汀若静

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值