题意简述:给定一个有数字组成的字符串,要求从里面删去k个数字后剩下的数尽可能小,求最小值。
输入:一个数字组成的字符串num,要删去的数量k
输出:所得到的数的最小值
示例:对于字符串“1432219”,要删去3个数,可以删去第2、3、4位,剩下的“1219”是最小的。
题解:
无论我们怎样操作,最终得出的数的位数是固定的(num的长度减去k),那么要让数尽可能小,就是要让高位的数字尽可能小。一个方法是,把数字小的位先找出了,然后按升序排列。但是这个方法忽略了一个问题:最后得出的数中那些数字的先后关系应该跟它们在原num字符串中一致。
为了保持这种先后关系,我们可以采取以下方法:
- 使用一个字符串res存放结果
- 从左到右遍历num,将当前的数字向后插入到res中,在此之前先把res中比这个数字大的数字从后到前依次弹出,每弹出一次记录一次,弹出的次数不能超过k次。这样就可以保证,得到的那一位数字肯定是最小值(因为之前占据着那一位的数字比它大,而且已经弹出,除非弹出次数已够)。
需要注意的细节:
- 有可能在原字符串中升序排列的情况比较多,导致弹出的次数不足k次,这时就取res的前(num的长度-k)位。
- 最后需要除去res的leading zero。
代码实现如下,该算法的时间复杂度是O(N+k)(遍历一次num,做k次弹出),空间复杂度是O(N)(存放结果的res)。
class Solution {
public:
string removeKdigits(string num, int k) {
string res;
auto keep = num.size() - k;
for(auto ch: num) {
while(k > 0 && res.size() > 0 && res.back() > ch) {
res.pop_back();
k--;
}
res.push_back(ch);
}
res = res.substr(0, keep);
auto it = res.find_first_not_of("0");
if (it != string::npos) res = res.substr(it);
else if(res.back() == '0') return "0";
if(res.size() == 0) return "0";
else return res;
}
};