文章目录
- 前言
- 一、买铅笔
- 二、影分身
- 三、三而竭
- 总结
前言
这回又换成C++了,Python要用C++也要用,没有哪个正经程序员只会一门语言的,咱可是CSDN认证带V的全栈攻城狮。今天的题目除了买铅笔都还是有点难度的,虽然影分身主要是考验阅读理解能力。
提示:以下是本篇文章正文内容,下面案例可供参考
一、买铅笔
题目描述
P老师需要去商店买n支铅笔作为小朋友们参加编程比赛的礼物。她发现商店一共有 3 种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同。为了公平起 见,P老师决定只买同一种包装的铅笔。 商店不允许将铅笔的包装拆开,因此P老师可能需要购买超过 n 支铅笔才够给小朋 友们发礼物。 现在P老师想知道,在商店每种包装的数量都足够的情况下,要买够至少 n 支铅笔最少需要花费多少钱。
输入描述:
第一行包含一个正整数 n ,表示需要的铅笔数量。 接下来三行,每行用 2 个正整数描述一种包装的铅笔:其中第 1 个整数表示这种 包装内铅笔的数量,第 2 个整数表示这种包装的价格。 保证所有的 7 个数都是不超过 10000 的正整数。
输出描述:
1 个整数,表示P老师最少需要花费的钱。
示例:输入n=57, {{2, 2}, {50, 30}, {30, 27}} 输出:54
代码如下(示例):
using namespace std;
string solution(int n, int arr[3][2]){
string result;
// TODO:
int minpay = 100000;
for (size_t i=0; i<3; ++i){
int tmp = arr[i][0];
while (tmp<n){
tmp += arr[i][0];
}
if ((tmp/arr[i][0])*arr[i][1] < minpay) minpay=(tmp/arr[i][0])*arr[i][1];
result = to_string(minpay);
}
return result;
}
笔者做的题全是在原有代码的基础上改的,虽然为这点被坑了好多回,可就是不肯改。所以这里只给出solution函数就行了。
这题还是很简单的,代码中tmp是在不拆包装的情况下会买到的铅笔数,这里用的加法,其实也可以写成乘法的。乘法要判断是否整除的情况,可以用n/arr[i][0]+bool(n%arr[i][0]),运行速度应该差距不大。代码中的minpay用来表示最少地花费,比较一下取最小值就行。 需要注意的是minpay的初始值取大点,用题目所述的10000是不行的,好像只能得40分,费了我好几分钟才想到这值取小了…
二、影分身
题目描述
已知字符串str。字符串str包含字符’x’,’y’。 如果相邻的两个字符不同,消除两个字符,优先从左边进行消除。 xyyx - > yx ->
输入描述:
输入多个字符。(1<=len<=1e5)
输出描述:
输出最后的分身
示例:输入:xyyyy 输出:yyy
代码如下(示例):
这是利用了stack栈的后入先出(LIFO)的特性来做的写法,这个办法是能满分的。具体的思路就是将要保留的字符压入栈中,再和后一个对比,如示例xyyyy:
首先,定义了输入栈out,循环i=0时,因为栈是空的,就将x压入,continue继续下一个循环。i=1循环时,out的top是x、str[i] 是y,所以栈中的x被弹出,下一个循环栈又是空的了,i=2 的y被压入,以此类摔倒…直到循环完成就得到了解,因为栈的特性,只能从顶端取出数据,所以写了一个while循环,把栈中的字符又重新组合成字符串。栈的速度是极快的,比数组都要快,而且非常简单易用!用得上的函数方法就pop、push、size、top,有一点要注意的是,它和Python的list的pop方法不一样,j=out.pop(),是取不到值的。这个方法返回的是void, top()才返回栈顶的引用。
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <stack>
using namespace std;
std::string solution(std::string str){
std::string result;
// TODO:
stack<char> out;
int l = str.length();
for (int i=0; i<l; ++i){
if (out.size()==0){
out.push(str[i]);
continue;
}
if (str[i] == out.top()){
out.push(str[i]);
}else{
out.pop();
}
}
while (out.size()){
char j = out.top();
result = j + result;
out.pop();
}
return result;
}
这题看了好久又多次测试才明白题意,它是每次消除以后要从新开始从左到右再计算的,不是第一次计算后保留下来的就一定会保留,还要再次和后面的字母比较,所以最终的结果只会有x或y。理解这一点后,就相对比较简单了,一开始笔者写了个递归来做,测试用例是没问题的。但实际执行会提示:terminate called after throwing an instance of 'std::bad_alloc'
内存分配不足了!果然递归不靠谱。这里也给出递归写法以供参考:
string reduce(string str){
int l = str.length();
if (l==0 || l==1){
return str;
}
for (int i=0; i<l; ++i){
if(str[i]==str[i+1] && i+1==l-1){
return str;
}
else if(str[i]!=str[i+1] && i+1<l){
str=str.substr(0,i)+str.substr(i+2,l);
break;
}
}
return reduce(str);
}
这个写法相对前面的代码显得很简洁,思路也简单,退出递归的条件是三个:一是消完了,二是只剩下一个字符,三是全部字符都一样。后面就是每次递归消除二个字符。测试发现不能过关,才改成stack栈的写法,说明测试用例中有极长的字符串。
三、三而竭
这题之前做过了,难度系数在笔者看来还是有点高的,当时也费了不少时间才解出来,主要是容易超时。是一个凑数字的题,暴力凑的方法,其中几个数的取值范围很重要。笔者也没有想出其它更好的办法,按这个解法用了600多ms的时间,算是免费过关。请见:
https://blog.csdn.net/alal001/article/details/130119027
总结
希望本文能对各位看官有所启发,原创文章,未经许可,请勿转载。