【刷题汇总 -- 添加逗号、跳台阶、扑克牌顺子】

今日刷题汇总 - day009

1、添加逗号

1.1、题目

在这里插入图片描述

1.2、思路

读完题,知道让我们将一个大整数,以逗号为分割且三位数为基准,进行划分为若干份以便提升大数的读识。那么通过思考示例分析,可以将str原字符串遍历,遍历同时尾插到retstr字符串,且每三位就增加一个逗号即可。思路其实不难,只需要注意一些细节的处理即可,这里我记录我的笨办法目的是,应用一些接口,也提供我写完后觉得很冗余的优化,接下来,就是程序实现。

1.3、程序实现

首先,按照题目要求完成输入,然后笨办法就是,按照思路遍历str大数字符串,遍历一位就尾插一位到retstr中,且每三位就尾插一个逗号,然后输出retstr,,结果提交后发现不能通过全部样例与实际要求不符。因为逗号的添加是从前向后进行尾插的。值得注意的是,这里i需要等于1,开始遍历,所以下标str[i-1]才能正确尾插,是为了使得i%3避免进来就尾插逗号。

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    string str;
    cin >> str;
    string retstr;
    size_t len = str.size();
    for (size_t i = 1; i <= len; i++)
    {
        retstr += str[i-1];
        if(i%3 == 0)
        {
            retstr += ',';
        }
    }
    cout << retstr << endl;
    return 0;
}

所以为了解决这个问题,我将原字符串先进行reverse逆置,再进行尾插操作。想着最后再逆置回来输出即可,然后提交发现,逗号虽然可以正确插入了,但是会将最开头的数字前也插入逗号。
在这里插入图片描述

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    string str;
    cin >> str;
    reverse(str.begin(),str.end());
    string retstr;
    size_t len = str.size();
    for (size_t i = 1; i <= len; i++)
    {
        retstr += str[i-1];
        if(i%3 == 0)
        {
            retstr += ',';
        }
    }
    reverse(retstr.begin(),retstr.end());
    cout << retstr << endl;
    return 0;
}

当时,没想着控制边界,笨办法就是调用erase把开头多余的逗号删除再逆置输出,虽然解决了问题,但是很冗余,且没必要,不过想着记录一下思考历程,熟悉一些其它接口的使用,所以还是写一下这个过程。

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    string str;
    cin >> str;
    reverse(str.begin(),str.end());
    string retstr;
    size_t len = str.size();
    for (size_t i = 1; i <= len; i++)
    {
        retstr += str[i-1];
        if(i%3 == 0)
        {
            retstr += ',';
        }
    }
    size_t retlen = retstr.size();
    if (retstr[retlen-1] == ',')
        retstr.erase(retstr.begin() + retlen -1, retstr.end());
    reverse(retstr.begin(),retstr.end());
    cout << retstr << endl;
    return 0;
}

在这里插入图片描述

在这里插入图片描述

1.4、程序实现 – 优化1

基于笨办法的基础,思考后发现直接在尾插时就可以控制最后逗号尾插的边界问题,即使得i != len即可。不用调用erase删除了。

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    string str;
    cin >> str;
    reverse(str.begin(),str.end());
    string retstr;
    size_t len = str.size();
    for(int i = 1;i <= len ;i++)
    {
        retstr += str[i-1];
        if(i%3 == 0 && i != len)
            retstr += ',';
    }
    reverse(retstr.begin(),retstr.end());
    cout << retstr << endl;
    return 0;
}

在这里插入图片描述

在这里插入图片描述

1.5、程序实现 – 优化2

继续思考,发现既然顺着控制3位是反着的,那么直接在尾插就以高位进行3位的控制不就行了吗?即,if((len-i-1)%3 == 0 && i != len-1)即可,且不用i从1开始了,也能正确尾插了。

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    string str;
    cin >> str;
    string retstr;
    size_t len = str.size();
    for(int i = 0;i < len ;i++)
    {
        retstr += str[i];
        if((len-i-1)%3 == 0 && i != len-1)
            retstr += ',';
    }
    cout << retstr << endl;
    return 0;
}

在这里插入图片描述
在这里插入图片描述

2、跳台阶

2.1、题目

在这里插入图片描述

2.2、思路

读完题,知道青蛙跳台问题属于比较经典的dp动态规划问题,求青蛙对于n个台阶,最多有多少种跳法。既然如此,使用dp就需要分析dp的状态表示和状态转移方程,根据题目示例分析不难得出:可以dp[i]表示,跳到第i个台阶可以最多拥有的跳法;其次推导dp状态转移方程:dp[i] = dp[i-1] + dp[i-2];因为只能由前一个台阶或前两个台阶才能有机会跳到第i个台阶,所以递推得出即可。此外,对于前两个台阶的跳法,很快知道,dp[0] = 0;dp[1] = 1;dp[2] = 2;由此dp思路就完成了。另外,这里还可以用递归的写法,使用递归只需要注意递归的终止条件和划分为子问题求解,所以本质也属于动态规划法,那么递归就是利用封装一个func函数,不断调用字节进行求值返回即可。接下来,就是程序实现。

2.3、程序实现 – dp

比较简单,根据思路分析的需要定义dp[N]数组,然后正确输入n个台阶,初始化推导的dp[0~2],所以直接从3个台阶开始累计即可。最后输出dp[n]就是n个台阶的最多方法。

#include <iostream>
using namespace std;
const int N = 41;

int dp[N];

int main() 
{
    int n;
    cin >> n;
    dp[0] = 0;
    dp[1] = 1;
    dp[2] = 2;
    for(int i = 3;i <= n;i++)
    {
        dp[i] = dp[i-1] + dp[i-2];
    }
    cout << dp[n] << endl;
    return 0;
}

在这里插入图片描述
在这里插入图片描述

2.4、程序实现 – 递归

那么递归程序也是按照思路,封装func执行调用逻辑,利用n=0,1,2控制递归终止条件且划分子问题return返回输出即可。

#include <iostream>
using namespace std;

int func(int n)
{
    if(n == 0)
        return 0;
    else if(n == 1)
        return 1;
    else if(n == 2)
        return 2;
    else 
        return func(n-1) + func(n-2);
}

int main() 
{
    int n;
    cin >> n;
    cout << func(n) << endl;
    return 0;
}

在这里插入图片描述
在这里插入图片描述

3、扑克牌顺子

3.1、题目

在这里插入图片描述

3.2、思路

读完题,知道让判断在一组扑克牌中,是否有顺子,且大小王用0表示,并可以替换为任意牌;其次,AJQK数值大小分别是1,11,12,13最大,即范围[0,13]。那么,基本思路分析示例看出,不能存在相同的数,这样一定不是顺子,然后,如果是顺子,那么最大的数减去最小的数之差是等于4的,此外,主要是对于大小王的处理,如果是最大与最小的数直之差大于4,那么0代替任何数都无法组成顺子,所以只有差值小于4,大小王才能替换成顺子。另外,还存在一些细节,接下来,就是程序实现。

3.3、程序实现

首先,搞懂思路分析后明白,主要是处理重复值以及大小王的替换规则,那么先根据需求,定义一个hash[]数组表示,是否存在重复值,然后定义maxval 和 minval表示除大小王以外的最大值和最小值,然后利用范围for遍历,如果不是大小王就判断是否已标记(是否是重复值),不是就标记已出现一次,然后更新最大值和最小值,遍历完,最后根据思路分析的大小王的替换规则,判断最大值和最小值的差值,是否小于等于4即可。

class Solution {
public:
    bool hash[14] = { false };
    bool IsContinuous(vector<int>& numbers)
    {
       int maxval = -1;
       int minval = 14;
       for(auto e : numbers)
       {
        if(e)
        {
            if(hash[e])
                return false;
            hash[e] = true;
            maxval = max(maxval,e);
            minval = min(minval,e);
        }
       }
       return maxval - minval <= 4;
    }
};

在这里插入图片描述
在这里插入图片描述

4、题目链接

添加逗号
跳台阶
扑克牌顺子

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值