蓝桥杯大赛— —每日一题(7、最优包含)

【问题描述】 本题总分:15 分
我们称一个字符串 S 包含字符串 T 是指 T 是 S 的一个子序列,即可以从
字符串 S 中抽出若干个字符,它们按原来的顺序组合成一个新的字符串与 T 完
全一样。
给定两个字符串 S 和 T,请问最少修改 S 中的多少个字符,能使 S 包含
T ?
【输入格式】
输入两行,每行一个字符串。第一行的字符串为 S,第二行的字符串为 T。
两个字符串均非空而且只包含大写英文字母。
【输出格式】
输出一个整数,表示答案。
【样例输入】
ABCDEABCD
XAABZ
【样例输出】
3
【评测用例规模与约定】
对于 20% 的评测用例,1 ≤ |T| ≤ |S | ≤ 20;
对于 40% 的评测用例,1 ≤ |T| ≤ |S | ≤ 100;
对于所有评测用例,1 ≤ |T| ≤ |S | ≤ 1000。
时间限制: 1.0s 内存限制: 256.0MB

【我的思路】

首先,很明显我们这道题要用到动态规划(dp)算法,动态规划简单来说就是要达到一个目标,中间的每个步骤都会影响到下一步的走法,为了找到最优的方法,所以这可以大大的降低时间复杂度。
对于这道题,我们可以设一个数组dp[i] [j]来存放S字符串中第i个字符之前的子串对比T字符串中第j个字符之前的子串至少需要修改多少个,可以想到dp[0][0]应该为0,因为相当于还没开始对比,所以不用修改,dp[i][0]也应该为0,因为……同理肯定也为0,也相当于还没开始对比嘛,但是,dp数组中其他的元素按理说都应该初始化为无穷大,因为题中说最少修改几个字符,那么我们可以用动态规划来解决时肯定是一步一步对比然后选择修改最少的字符,那么数组如何初始化为无穷大呢?这里我们就要用到 memset()函数,它是按照字节数来初始化的,具体怎么用可以问度娘。那么关键问题是我们然后一步一步对比呢?
首先当然是两层循环将S和T字符串中的没个字符爱格对比,然后看他们一样不,一样的话那么对应的dp数组元素肯定就为前一个dp元素的值不变,要是不一样,那么要么改变T中的一个字符(相当于dp[i-1][j-1]+1),要么就回到上一层中的那个元素的值(dp[i-1][j]),具体的哪个小就用哪个。不理解的话看看代码应该就差不多了。
代码如下

#include<iostream>
using namespace std;

char s[1000], t[1000];
int dp[100][100];
int main() {
    cin >> s + 1 >> t + 1;
    int n = strlen(s + 1), m = strlen(t + 1);
    memset(dp, 0x3f, sizeof dp);//至于为什么是0x3f,可以去看看整型字节数以及可以存储最大数的(要先明白memset()函数的用法)
    
    dp[0][0] = 0;

    for (int i = 1; i <= n; ++i)
    {
        dp[i][0] = 0;
        for (int j = 1; j <= m && j <= i; ++j)
        {
            if (s[i] == t[j]) 
            {
                dp[i][j] = dp[i - 1][j - 1];
            }
            else 
            {
                dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1] + 1);
            }
        }
    }
    cout << dp[n][m] << endl;
}

我接下来到蓝桥杯 比赛这段时间尽量每天做一道往年题目或者找到合适的发上来,一方面监督自己,一方面求大佬指正,希望一起进步一起学习哈!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值