强化训练:day2(牛牛的快递、最小花费爬楼梯、数据中两个字符串的最小距离)

前言

  今天的内容比昨天的稍难一些,今天涉及到了dp问题,本来之前是打算先写一些算法总结的,但是时间不太充裕,就没写,以后我再补上。补不补都是后话了,我们先来看今天的内容。

1. 牛牛的快递

  先来一个简单题热热身,做题链接:BC64 牛牛的快递

1.1 题目描述

在这里插入图片描述

1.2 解题思路

  这道题就是一道简单的模拟题,就根题上说的一步一步写就可以了。可以先不考虑加急不加急,先计算不加急的情况下要花费多少money,再判断是否加急,如果加急,再在结果上加上5个圆子就可以了。
  对于不足1kg的按1kg算这一问题,可以用一个整数保存一个浮点数的整数部分,然后再将整数与浮点数进行比较,如果相等,说明它就是一个整数,如果不相等,就说明它是个浮点数,需要在结果加上1kg的费用。

1.3 代码实现

#include <iostream>
using namespace std;
int solve(double n) {
    if (n > 1) {
        double m = n - 1;
        int t = n - 1;
        if (m > t) return 20 + t + 1;
        else return 20 + t;
    }
    return 20;
}
int main() {
    double a;
    char b;
    cin >> a >> b;
    int ret = solve(a);
    if (b == 'y') cout << ret + 5;
    else cout << ret;
    return 0;
}

2. 最小花费爬楼梯

  做题链接:DP4 最小花费爬楼梯

2.1 题目描述

在这里插入图片描述

2.2 解题思路

  这就是简单的线性dp问题,当你发现要找出结果有很多种情况时,就可以考虑dp解决。
  就比如这道题,我们直接抽象出一个具体的例子来看,比如台阶一共有5个,我们从第1个或者第2个台阶出发,一次可以走上1个台阶或者2两个台阶,意味着我们可以到达第3个台阶(1->3或者2->3)或者第4个台阶(2->4),而到达第5个台阶就是3->5或者4->5,到达顶部就是4->顶部或者5->顶部。
  我枚举一下:1->3->4->5->顶,1->3->5->顶,2->3->4->5->顶,2->4->5->顶,2->3->5->顶,2->4->顶,等等很多情况,而且你还并不知道每一个台阶的费用,并不是台阶越少花费就越小, 比如2,4台阶每个花费100块,1,3,5台阶每个花费1块,,结果显而易见。
  每走一步都有很多中情况(状态)可以选择,这既是dp问题的标志。
  我们来看这个题,当遇到第n个台阶时,我们可以选择从第n-1个台阶上来,也可以选择从第n-2个台阶上来, 因此我们可以选择两种方式中花费最小的一种方式上来,也就是我们可以用一个dp[n]来表示:到达第n个台阶所需要的最小花费,它的结果是什么呢?那就是 dp[n] = min(dp[n-1] + cost[n- 1],dp[n-2] + cost[in- 2]),也就是从到达dp[n-1]个台阶和到达dp[n-2]个台阶中,选择小的那一个填到dp[n]。不过比较时还需要加上所走台阶的费用。
  大家可以自己用测试用例,通过走读代码的方式来细细体会,因为光用文字描述很难表达(我就是通过走读代码的方式慢慢理解dp问题的,虽然很费力,但是很好用)。
  dp问题中,最最重要的是状态表示和状态转移方程,在这个题中状态表示就是:到达第n个台阶所需要花费的最小费用,状态转移方程是:dp[n] = min(dp[n-1] + cost[n- 1],dp[n-2] + cost[in- 2])

2.3 代码实现

#include <iostream>
using namespace std;
#include <vector>
int main() {
    int n = 0;
    cin >> n;
    vector<int> cost(n + 1, 0);
    for (int i = 0; i < n; i++) cin >> cost[i];
    vector<int> dp(n + 1);
    dp[0] = dp[1] = 0;
    for (int i = 2; i <= n; i++) 
    {
        dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
    }
    cout << dp[n];
    return 0;
}

3. 数组中两个字符串的最小距离

  做题链接:数组中两个字符串的最小距离

3.1 题目描述

在这里插入图片描述

3.2 解题思路

  这道题是要求时间复杂度为O(n),空间复杂度为O(1),也就是说我们只能循环一次,并在在原地上进行解决问题。
  可以使用两个指针cur1和cur2,一个标记str1,一个标记str2,每遇到新的str1或者str2,并且当前cur 的值合法的,都对最后的结果进行更新,然后再将cur也进行更新。

3.3 代码实现

#include <iostream>
using namespace std;
#include <string>
int main() {
    int n = 0;
    cin >> n;
    string str1, str2, s;
    cin >> str1 >> str2;
    int cur1 = -1, cur2 = -1, ret = 0x3f3f3f3f;
    for (int i = 0; i < n; i++) {
        cin >> s;
        if (s == str1) 
        { // 去前⾯找最近的 s2
            if (cur2 != -1) 
            {
                ret = min(ret, i - cur2);
            }
            cur1 = i;
        } 
        else if (s == str2) 
        { // 去前⾯找 s1
            if (cur1 != -1) 
            {
                ret = min(ret, i - cur1);
            }
            cur2 = i;
        }
    }

    if (ret == 0x3f3f3f3f) cout << -1;
    else cout << ret;
    return 0;
}

总结

  今天的比昨天的难度增加了一些,但是也还好,主要是dp问题,如果看不懂题解的话,可以先走读代码顺一遍过程,再来看题解,相信你会有新的理解。
  那么第二天的内容就到此结束了,希望自己可以继续坚持下去,也希望能与大家共同进步,如果大家发现有什么错误的地方,可以私信或者评论区指出喔。我会继续坚持训练的,共勉!!!那么本期就到此结束,让我们下期再见!!觉得不错可以点个赞以示鼓励!!

  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不如小布.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值