题目: AcWing 1453. 移掉K位数字
给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。
注意:
空字符串被视为0。
如果结果中包含前导零,则需要将前导零删除,最后删除的前导零不用包含在移除的 k 个数字中。
输入格式
第一行输入一个字符串,用来表示非负整数 num。
第二行输入一个整数,表示 k。
输出格式
输出一个字符串,表示移除 k 位数字后所能得到的最小数字。
数据范围
0≤k≤ 字符串长度 ≤100000,
num 中不包含任何前导 0。
输入样例1:
1432219
3
输出样例1:
1219
样例1解释
移除掉三个数字 4,3,2 可形成一个新的最小的数字 1219。
输入样例2:
10200
1
输出样例2:
200
样例2解释:
移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
输入样例3:
10
2
输出样例3:
0
样例3解释
从原数字移除所有的数字,剩余为空就是 0。
题目分析:(贪心+单调栈)
第一种递增的情况
如图可知,如果是递增那么我们删除最后几位即可
第二种一般情况
如图可知,如果我们碰到逆序,我们可以选择删除前面一位,或者不删除
因为位数相同,如果我们不删除则当前位一定大于删除,所以我们选择删除
思考:那么不是有前导0的情况吗?
其实前导0的情况已经包含在一般情况,因为有0,则前面肯定是逆序,优先删除前面
#include <iostream>
using namespace std;
int main()
{
string num;
int k;
cin>>num>>k;
string res="0"; // 避免处理边界
for(int i=0;i<num.size();i++)
{
while(k&&res.back()>num[i]) // 处理逆序
{
res.pop_back();
k--;
}
res+=num[i];
}
while(k)res.pop_back(),k--; // 如果还剩余k,将后面删掉
int i=0;
while(i<res.size()&&res[i]=='0')i++; // 定位 去掉前导零的位置
if(i==res.size())cout<<"0"<<endl;
else cout<<res.substr(i)<<endl;
return 0;
}