删数问题
删数问题
1. 题目
2. 题目解析
我们先给一些案例,然后寻找其中的规律:
1. 12345,如果我们删除一个数,使得数字最小。我们应该删除5。如果我们删除两个数,使得数字最小。我们应该删除4和5。
因此,如果数字的每一位都是递增的,我们应该删除最后的数字(第一种规则)。
2. 178543,如果我们删除一个数,使得数字最小。我们应该删除谁呢?如果我们删除1,结果为78543。如果我们删除7,结果为18543。如果我们删除8,结果为17543....。很明显,在删数的过程中,我们要尽可能地保证:删除后的结果高权的数字尽可能小。所以,我们要删除8。
对于结果中的第一位(最高位):如果我们删除1,那么最高位就是7。如果我们删除78543当中的任何一个数字,最高位都是1。因此,在删数的时候,我们不能把1删除。
对于结果中的第二位:如果我们删除7,那么第二位就是8。如果我们删除8543中的任何一个,第二位就是7。因此,为了保证删除之后的数最小,我们不可以删掉7。
对于结果中的第三位:如果我们删除8,那么第三位就是5。如果我们删除543当中的任何一个,第三位仍然是8。因此,8应该被删除。
...
那么我们可以找一下规律:178543,8正好是从左往右第一个比右边的数(5)大的数。因为存在逆序(85)。
那么可能有人会问:178543存在两个逆序:85和43。为什么删除了8不考虑4?很简单:因为8的权重比4大。在比较数字时,我们优先会考虑权重大的数。
3. 如果178543当中,删除两个数。我们应该删除谁?第一个删除8,结果为17543。第二个应该删除7。
4. 因此,我们总结第二个规律(第二个规则):如果数字的每一位不是单调递增的,我们应该删除从左往右第一个比右边的数大的数(逆序)。
5. 还需要考虑一个问题:有些数删除之后可能会有前导0的问题。因此,我们还需要去除前导0。
例如:10035,删掉一个数。我们应该删掉1。结果就是0035->35
3. 题解
#include <iostream>
#include <cstdio>
using namespace std;
int main(){
string n;
int k,i;
cin >> n >> k;
//第二种规则
while(k){
for(i = 0;i < n.size() - 1; i ++){
if(n[i] > n[i+1]){
n.erase(i,1);
k--;
break;
}
}
if(i == n.size() - 1){
break;
}
}
//第一种规则
while(k){
n.pop_back();
k--;
}
//删除前导0
while(n[0] == '0' && n.size() > 1){
n.erase(n.begin());
}
cout << n;
return 0;
}
4. 参考文献
1. 上图的课件来自于中国科学院大学马丙鹏老师的计算机算法设计与分析课程。
2. https://www.bilibili.com/video/BV1Mp4y1B7g1/?spm_id_from=333.337.search-card.all.click&vd_source=a642bb3ddc5b706845426dc41d73fbda
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现