目录
一、题目描述
给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。
注意:
- num 的长度小于 10002 且 ≥ k。
- num 不会包含任何前导零。
示例 1 :
输入: num = "1432219", k = 3
输出: "1219"
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。
示例 2 :
输入: num = "10200", k = 1
输出: "200"
解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
示例 3 :
输入: num = "10", k = 2
输出: "0"
解释: 从原数字移除所有的数字,剩余为空就是0。
二、解题思路
本题的难点在于怎么找数,要使找到的数尽可能的小且不能改变相对的顺序,就意味着从左往右的遍历,对于当前正在遍历的数而言,如果前面的数比它大,那就要将其移除,这样新得到的数会更小,举例来说,1432219,如果现在遍历到的数是3,那么前面的4就要移除,因为14开头的数会比13开头的数大,同样当遍历到2时,前面的3就要移除,因为13开头的数要比12开头的数大;对每一个数字都进行这样的操作,最终得到结果。
如果想到了上述的操作流程,那么数据结构也就好选了,满足后进先出的结构那就是栈了。
还有一些细节需要注意的是,此题在遍历过程中并不一定能把所有要移除的数都找出来;还要注意结果中的前导0的处理。
到这里,这道题基本上就没有什么问题了。
三、代码实现
#include<bits/stdc++.h>
using namespace std;
string removeKdigits(string num, int k) {
int n = num.size();
if (k == n) return "0";
if (k == 0) return num;
string res;
//如果不想后面在逆置的话,可以用vector(只要前后都可以出入数据的数据结构就行)代替
stack<char> chSta;
chSta.push(num[0]);
for (int i = 1; i < n; ++i) {
//这里要注意,必须是栈顶元素大于当前值才弹出,等于不弹出,否则特殊情况的答案不正确
while (!chSta.empty() && chSta.top() > num[i] && k) {
chSta.pop();
k--;
}
chSta.push(num[i]);
}
//如果弹出的数量没有K个,说明数据中间是维持升序的(比如一个升序的序列:112345)
//那么要删除的数据处在末尾,弹出末尾对应的数量的数字即可
while (k){
chSta.pop();
k--;
}
//拿出栈中的数据放到string中
while (!chSta.empty()) {
res += chSta.top();
chSta.pop();
}
//逆置string
reverse(res.begin(), res.end());
//处理开头的‘0'
if (res[0] == '0') {
for (string::iterator it = res.begin(); it != res.end(); ) {
if (*it == '0') {
it = res.erase(it);
} else
break;
}
}
if (res == "") return "0";
return res;
}
int main() {
string num = "113";
num = removeKdigits(num, 2);
cout << num;
return 0;
}
强调一下:单调栈的使用一定是栈顶元素大于当前数才弹出,否则在特殊情况时的结果是不对的,要注意这个坑,调了一上午……