1.题目
删数问题
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
键盘输入一个高精度的正整数n(≤100位),去掉其中任意s个数字后剩下的数字按照原来的左右次序组成一个新的正整数。编程对给定的n与s,寻找一种方案,使得剩下的数字组成的新数最小。
Input
输入有多组 每组包括原始数n,要去掉的数字数s;
Output
输出去掉s个数后最小的数
Sample Input
178543 4
Sample Output
13
2.正确代码
#include <iostream>
#include <string>
using namespace std;
int main()
{
string a;
int k,i;
while(cin >> a >> k)
{
while(k--)
{
i=0;
while(i<a.length()&&a[i]<=a[i+1]) i++;
a.erase(i,1);
}
//对字符串零进行处理。
while(a[0]=='0'&&a.length()!=1)
a.erase(0,1);
cout << a << endl;
}
return 0;
}
3.代码解读:
首先,我们先要明确贪心算法的核心,然后再来分析这个问题设置一个正确的贪心算法。
如何设计最小数呢?
我们先从广义上理解这个。
1.当然是删除最大的啦。
2.之后,将这些数字从小到大排列起来。
当这一串数字固定时如何来删除呢?
1.思考一个关键问题,对一个数来讲,其大小和什么有关?难道仅仅是取决于最大数吗?当然不是啦,而是取决于最高位的大小啊。
2.所以,对于一个数来讲,其每位数的最大值是次要的,而其数字所在的权位才是重要的。
3.好,既然谈到权位,对于一个相对位置已经固定下来的数字来讲,如何让它值最小呢?答案当然是尽量是权位越高的数字越小。
4.只要你理解上面的那句话,那么表现在数字上是升序排序,这是非常重要的。我们只要尽量保证这串数字是升序排序,那么就说明,在当下是最优选择,如果删除目前这位,那么会导致后面的更大的数字来占据这个权位,那么这个数会变大。
5.还有一点,你是应该明确的,那就是,我们只能做到删除数字,无法添加数字,也不能对数字的相对位置做出更改。所以,我们是当下的最优解,我们尽量保证是升序即可,如果发现降序数字,我们就要删除这个最大值,如 1 3 2 我们要删除3,让降序后面更小的数来补齐这个位,会让数字变得更小。
6.所以,我们所做出的一切操作都是为了让数字变得更小,当我们发现一个降序,可以让数字变的更小,所以,我们就要立刻行动起来,把更小的数掉到权更大的位来使数字变得更小,就是这个样子,很好理解。
7.如果整个数字满足升序了,因为我们还要删除数字,这时,我们应该删除哪个呢?因为升序,我们如果删除其中的任何一个,那么后面的比它大的数来补上,权位会变大,这样就会让数变大!如何不用补呢?答案很简单,就是对最后一位来进行删除,所以这个整体的算法就解决出来了。
处理细节
对于C++,我们要明确如何删除字符串类型的单个字符,同时,我们还应该理解如何对零的处理,这个是有很多技巧的,比如10002删除两个数,最后应该为0,必须保证字符串至少有一个为一个,就是这个意思,理解就好。