保留最大的数(C++)
题目描述
给定一个十进制的正整数number,选择从里面去掉一部分数字,希望保留下来的数字组成的正整数最大。
输入描述:
输入为两行内容,第一行是正整数number,1 ≤ length(number) ≤ 50000。第二行是希望去掉的数字数量cnt 1 ≤ cnt < length(number)。
输出描述:
输出保留下来的结果。
示例1
输入
325 1 |
输出
35 |
看到这个题之后,作为一个刚学了一个月C++的菜鸡,我最初的想法非常简单粗暴,就是想办法找到最小的那个数,然后把它删除,这样就能保留最大的数。
#include <bits/stdc++.h>
using namespace std;
//第一代
int main()
{
string number;
int cnt;
cin >> number >> cnt;
while(cnt--)
{
//找最小的数字所在位置
int len = number.length();
int minIndex = 0;
for(int i=0;i<len;i++)
{
if(number[i] < number[minIndex])
{
minIndex = i;
}
}
//删除数组中的元素
for(int i=0;i<len;i++)
{
if(i==minIndex)
{
number.erase(i,1);
}
}
}
cout << number << endl;
return 0;
}
这个算法只能通过牛客网上30%的测试用例。比如当输入"123450 1"时,我们预期的答案应该是23450,但是算法是通过找出最小的数字所在位置,再把它删除来获取最大值的。算法得出结果是12345,显然算法还存在缺陷。
这就有点尴尬了,问了下学姐,她说试试从最高位开始把相邻的两个数字作比较,如果前一位比后一位小就删掉前一位,因为要使一个数大的话 尽量让最高位大就行了。于是我在第一代的基础上修改之后,写出了这道题第二代算法。
#include <bits/stdc++.h>
using namespace std;
//第二代
int main()
{
string number;
int cnt;
cin >> number >> cnt;
while(cnt--)
{
//找最高位且大于次位的数字所在位置
int len = number.length();
int Index = 0;
for(int i=0;i<len-1;i++)
{
if(number[i] < number[i+1])
{
Index = i;
break;
}
}
//删除数组中的元素
for(int i=0;i<len;i++)
{
if(i==Index)
{
number.erase(i,1);
}
}
}
cout << number << endl;
return 0;
}
第二代不愧是第二代,它能通过牛客网上80%的测试用例。好尴尬啊,问题出在哪呢? 经过多次调试可以发现,当Index没有发生改变时,这个算法就会出错。比如当输入"543210 1"时,Index一直等于零,所以在删除元素的时候,最高位会被直接删除,从而得到结果43210,这与我们预期的结果54321不同。
这可咋办呢? 在思考片刻之后,case通过率30%+80%会不会等于100%呢?然后我把第一代算法和第二代算法结合在一起,写出来了这题的第三代算法,果然全部AC。
#include <bits/stdc++.h>
using namespace std;
//第三代
int main()
{
string number;
int cnt;
cin >> number >> cnt;
while(cnt--)
{
//找最高位且大于次位的数字所在位置
int len = number.length();
int Index = 0;
bool flag = true; //flag为真,说明Index没有变过
for(int i=0;i<len-1;i++)
{
if(number[i] < number[i+1])
{
Index = i;
flag = false;
break;
}
}
//如果Index从没变过
if(flag)
{
//找最小的数字所在位置
int len = number.length();
Index = 0;
for(int i=0;i<len;i++)
{
if(number[i] < number[Index])
{
Index = i;
}
}
}
//删除数组中的元素
for(int i=0;i<len;i++)
{
if(i==Index)
{
number.erase(i,1);
}
}
}
cout << number << endl;
return 0;
}
额 顺便简述一下string.erase()函数的使用,如下:
erase函数的原型 | erase函数的用法 | erase函数的文字解释 |
(1)string& erase ( size_t pos = 0, size_t n = npos ); | erase(pos,n); | 删除从pos开始的n个字符 |
(2)iterator erase ( iterator position ); | erase(position); | 删除迭代器位置处的单个字符, 并返回下个元素 的迭代器 |
(3)iterator erase ( iterator first, iterator last ); | erase(first,last); | 删除迭代器[first, last) 区间的所有字符,返回一个指向被删除的最后一个元素的下一个字符的迭代器 |
直到这篇博文写完,我还是不敢相信这居然是2017校招真题。。。。。
膜拜某大佬简洁明了C++的代码,20行真的牛批。。。可能是因为我还没真正地理解erase()这个函数的精髓。
好了,时候不早了,大家晚安。