题目描述
给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。
示例 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 。
提示:
- 1 <= k <= num.length <= 105
- num 仅由若干位数字(0 - 9)组成
- 除了 0 本身之外,num 不含任何前导零
思路
首先,无论移除哪k位,移除后数字的位数是一样的,依然是remain位(假设先允许前导0存在)。
那么,最简单粗暴的方法是,枚举移除k位数字的后的所有可能,然后遍历一遍选择出最小的。但是,这样的方法在num位数较多的时候,移除k位后的可能呈指数增长,时间复杂度和空间复杂度都接受不了。所以,本题的难点在于如何快速判断应该移除哪k位。
对于2个数位相同的数组,大小只取决于从高到低第1个对应位置上不同数字。例如整数157a690 和 157b690,大小只取决于第1个对应位置上不同数字,这里就是 a 和 b。
所以本题可以使用单调栈的思想,如果第m位数字 > 第m+1位数字,那么移除第m位数字是划算的,因为可以让这一位的数字变小,因为位数从高到低刚好是从左往右,所以按照顺序遍历时,刚好是先处理高位,即影响更大的位置。
我们的策略是,定义1个栈stack,从高到低遍历原始数字,如果这1位数字 < 当前栈顶数字,我们就移除栈顶元素,直到栈为空或者 当前值 >= 栈顶元素。注意,移除最多只能k位,如果已经移除k位了,就不再执行移除逻辑。
当然,另一种情况下,维护完整个单调栈,移除的数量还不到k位,那么我们取出单调栈的数值并取前remain = len - k位即可。因为这里要按照放入的顺序取出栈中的元素,我们可以按照普通栈取出后在reverse,或者使用双端队列来替代栈,直接按照顺序来取出。
最后,还要注意结果存在前导0的情况,要去除前导0。
我们用图来展示一下上面的方法,更加直观:
Java版本代码
class Solution {
public String removeKdigits(String num, int k) {
int remain = num.length() - k;
if (remain == 0) {
return "0";
}
// 无论移除哪k位,移除后数字的位数是一样的,依然是remain位(假设先允许前导0存在)
// 2个位数一样的数字,大小只取决于从高到低第1个对应位置上不同数字
// 如果 第m位数字 > 第m+1位数字,那么移除第m位数字是划算的
Deque<Integer> deque = new LinkedList<>();
for (char c : num.toCharArray()) {
int val = Integer.parseInt(String.valueOf(c));
while (k > 0 && !deque.isEmpty() && deque.peekLast() > val) {
deque.pollLast();
k--;
}
deque.offerLast(val);
}
// 从双端列队中获取前remain位数字,同时去除前导0
StringBuilder ans = new StringBuilder();
// 前导0标识,如果是false,证明前面已经有不是0的数字了
boolean startZero = true;
for (int i = 0; i < remain; i++) {
int val = deque.pollFirst();
if (val == 0) {
// 当前数字是0,要判断前导0标识,如果是true,证明是前导0,不能添加到ans中;否则,前面已经存在不是0的数字了,可以添加
if (!startZero) {
ans.append(val);
}
} else {
// 当前数字不是0,如果前导0标识是true,要修改为false
if (startZero) {
startZero = false;
}
ans.append(val);
}
}
// 去除前导0后,可能全部被去除
if (ans.length() == 0) {
return "0";
}
return ans.toString();
}
}
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情