Coding Practice,48天强训(9)

Topic 1:添加逗号

像这种题就是应该简单题简单做,刚拿题目我还在考虑用rbegin() rend()来倒着遍历,鼓捣了半天结果insert()不能搭配反向迭代器使用,只能搭配正向迭代器,还不如直接用数组

#include <iostream>
#include <string>

using namespace std;

int main() 
{
    string str;
    cin >> str;

    size_t len = str.length();

    for(int i = len - 3; i > 0; i -= 3)
    {
        str.insert(i, ",");
    }

    cout << str << endl;

    return 0;
}

Topic 2:跳台阶

也是一个经典中的经典,跳台阶 | 爬楼梯 | 最小花费爬楼梯,动态规划+斐波那契的问题,需要反复复习

首先还是先确定dp数组的含义   dp[n] —— 达到第 n 阶台阶,有dp[n]种方式

然后确定递推公式,每次只能走1 or 2 步长,那么达到dp[n]就可以由dp[n - 1]和dp[n - 2]推出 ,也只和这前两阶有关,可以画个图看看

由于步长的关系(1or2步),每一阶的关系也只和前两阶有关,从1阶开始,1阶之前只有地面,所以只有1种方式到1阶,走1步(绿色);

2阶可以从1阶上,也能从地面上(红色),所以是1(到1阶有1种方式)+ 1 = 2种;

3阶则是能从1阶和2阶到达(蓝色),也就是1(到1阶有1种方式)+ 2 (到2阶有2种方式)= 3种;

同理,4阶(紫色)就是(到2阶有2种方式)+(到3阶有3种方式) = 5种

5阶(橙色)就是(到3阶有3种方式)+(到4阶有5种方式) = 8种,依此类推

所以公式就是dp[n] = dp[n - 1] + dp[n - 2],接下就可以做初始化了,那么dp[0]应该初始化为多少?才方便往上推呢?根据 dp[n] —— 达到第 n 阶台阶,有dp[n]种方式 的含义,应该是dp[1] = 1, dp[2] = 2, 比较合理

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param number int整型 
     * @return int整型
     */
    int jumpFloor(int number) 
    {
        // dp[n] = dp[n - 1] + dp[n - 2]
        if (number <= 1) return 1; // 1阶台阶,只有1种方式
        vector<int> dp(number + 1);
        dp[0] = 1;// 实际上是没有意义的,只是为了防止边界溢出
        dp[1] = 1;
        dp[2] = 2;
        for(int i = 2; i <= number; ++i)
        {
            dp[i] = dp[i - 1] + dp[i - 2];
        }

        return dp.back();
    }
};

更直观,其实就是斐波那契的写法了

class Solution {
public:
    int jumpFloor(int number) {
        if (number <= 1) return 1;// 输入如果是0阶 1阶返回1 对应斐波那契
        int a = 1, b = 1, c;// a 0阶   b 1阶   
        for (int i = 2; i <= number; ++i) // 从2阶开始算
        {
            c = a + b;// 2阶 = 0阶 + 1阶
            a = b;// 0阶变1阶
            b = c;// 1阶变2阶
            //循环往复,直至最后到要求的number数
        }
        return b;// 输出这一阶的方法数
    }
};

其实这个题目还有个比较有意思的衍生可以推一推,就是当每次不止走1or2步,要是每次最多能走m步,怎么推呢?

基础动态规划

int jumpFloorM(int n, int m) {
    if (n <= 1) return 1;
    vector<int> dp(n + 1, 0);
    dp[0] = 1; // 初始条件
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m && j <= i; ++j) {
            dp[i] += dp[i - j];
        }
    }
    return dp[n];
}

滑动窗口优化,先码住,之后有时间再回来分析

int jumpFloorM(int n, int m) {
    if (n <= 1) return 1;
    vector<int> dp(n + 1, 0);
    dp[0] = 1;
    dp[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (i <= m) {
            // 前 i 项和(dp[0]到dp[i-1])
            dp[i] = 2 * dp[i - 1];
        } else {
            // 滑动窗口:dp[i] = dp[i-1] * 2 - dp[i - m - 1]
            dp[i] = 2 * dp[i - 1] - dp[i - m - 1];
        }
    }
    return dp[n];
}

Topic 3:扑克牌顺子

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param numbers int整型vector 
     * @return bool布尔型
     */
    bool IsContinuous(vector<int>& numbers) 
    {
        //规律
        //1 不能有重复非零数字
        //2 最大数-最小数不能超过5,每个数字连续的话差值就是1嘛,1 2 3 4 5  5-1 = 4    5 6 7 8 9  9-5 = 4
        //3 数组长度为5,很多人觉得反证不好证明就是因为忘了这个条件,当然题目已经规定了只有五张牌
        //本题中,有两个非零数满足1、2两个条件就可以判定为顺子了,这就是确认极值来划定范围的思路
        sort(numbers.begin(), numbers.end());// nlogn就是因为这个sort,用哈希可以到N
        int zero = 0;// 计数0
        for (int i = 0; i < 4; ++i) 
        {
            if (numbers[i] == 0) ++zero;
            if (numbers[i] != 0 && numbers[i + 1] != 0 && numbers[i] == numbers[i + 1]) return false;
        }
        if(numbers[4] - numbers[zero] < 5) return true;
        return false;
    }
};

思路理好了代码可以写的很简单

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值