删数问题
题目描述
键盘输入一个高精度的正整数 N N N(不超过 250 250 250 位),去掉其中任意 k k k 个数字后剩下的数字按原左右次序将组成一个新的非负整数。编程对给定的 N N N 和 k k k,寻找一种方案使得剩下的数字组成的新数最小。
输入格式
输入两行正整数。
第一行输入一个高精度的正整数 n n n。
第二行输入一个正整数 k k k,表示需要删除的数字个数。
输出格式
输出一个整数,最后剩下的最小数。
样例 #1
样例输入 #1
175438
4
样例输出 #1
13
基本思路
要想得到最小的数,我们应该让第一位的数最小。于是,可以从高位开始删数。
具体实现过程:每次循环,在 k + 1 k + 1 k+1个数的范围内找最小值,并删除最小值之前的所有数(这是因为如果在 k + 2 k + 2 k+2范围内找的话,如果最小值是第 k + 2 k + 2 k+2个数,那么就不够删了)。然后将这次找到的最小字符输出,0字符不输出。循环结束如果什么都没有,就输出0。
代码
#include <iostream>
#include <string.h>
using namespace std;
int main () {
char a[250];
int k;
cin >> a >> k;
int len = strlen(a);
bool flag = 0; // 输出字符串开头是否非零
int begin = 0; // 遍历开始位置
int rest = len - k; // 剩余需要输出字符的数量
int cnt = 0; // 输出字符数量(包含0)
while (cnt < rest) {
char min = a[begin];
int idx = begin;
for (int i = begin; i <= begin + k; i++) {
if (a[i] < min) {
min = a[i];
idx = i;
}
}
k -= idx - begin;
begin = idx + 1;
cnt++;
if (min != '0') {
flag = 1;
}
if (flag) cout << min;
}
if (flag == 0) cout << 0;
return 0;
}
Note
代码中有一些细节值得注意:
- 循环结束条件不能用 k = = 0 k == 0 k==0 来进行判断。因为k为零并不意味着所有剩余字符都输出了。
if (min != '0') { flag = 1; } if (flag) cout << min;
这行代码我原来写做
if (min != '0') { flag = 1; cout << min;}
原来的写法是错误的。因为flag的意义是表明输出字符串开头是否非零,只要开头非零,后面均可以直接输出。原来的写法中,当已经有非零字符开头时,0字符无法正常输出。- 当发现多个最小值时,应该取最左侧的为min。例如样例: 174132838935 17413283893 5 174132838935 如果将下标为3处的1作为最小值,那么答案显然错误。
- 今天还学习了c语言风格的字符串:
#include <string.h>
strcmp(a, b); //比较,如果a>b,输出1;a<b,输出-1;a==b,输出0
strcpy(a, b); //将b复制给a
strlen(a); //a的长度,这种方法
可以返回字符数组的实际长度,当遇到\0字符时会停止计数
strcat(a, b); //将b连接到a后面
strchr(a, ch); //返回a中ch出现位置的指针
strstr(a, str);