1. 题目
给你一个以字符串表示的非负整数 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 不含任何前导零
Related Topics 栈 贪心算法 字符串 单调栈
👍 590 👎 0
2. 题解
2.1 解法1: 单调栈
维护一个单调递增的栈, 用于存储字符, 然后遍历字符串中每一个字符
- 每次将该字符与栈顶的元素比较大小, 若 当前字符小, 那么出栈元素, 直到满足条件, 将当前元素入栈
- 每次出栈一个元素, 相当于删除了一个元素, 需要将 k–, 若k提前为 0, 则不再执行出栈
- 遍历结束时,有可能还没删够 k 个字符,开个循环继续出栈,删低位。
最后如果栈变空了,什么也不剩,则返回 “0”。
否则,将栈中剩下的字符,转成字符串返回。
注意点: - 能会出现 1, 0 的情况, 这时 0 可能会作为栈底元素, 这样就不是数字了, 需要排除
- 遍历结束时,有可能还没删够 k 个字符,开个循环继续出栈,删低位
下面使用 StringBuilder 模拟栈, 注意每次出栈使 k-1, 直到 k为0, 同时需要排除栈底为空且字符为 0
的情况, 遍历结束后, 需要删去k之后的元素为返回结果
class Solution {
public String removeKdigits(String num, int k) {
if (num.length() == k) return "0";
StringBuilder stack = new StringBuilder();
for (int i = 0; i < num.length(); i++) {
char c = num.charAt(i);
while (k > 0 && stack.length() != 0 && stack.charAt(stack.length() - 1) > c) {
stack.deleteCharAt(stack.length() - 1);
k--;
}
if (c == '0' && stack.length() == 0) continue;// 避免栈底为 '0' 的情况
stack.append(c);
}
String res = stack.substring(0, stack.length() > k ? stack.length() - k : 0);
return res.length() == 0 ? "0" : res;
}
}
参考: 一招吃遍力扣四道题,妈妈再也不用担心我被套路啦~
写法2:
class Solution {
public String removeKdigits(String num, int k) {
Deque<Character> stack = new ArrayDeque<>();
for (char c : num.toCharArray()) {
while (k > 0 && !stack.isEmpty() && stack.peekLast() > c) {
stack.pollLast();
k--;
}
// 注意排除栈底为 '0' 的情况
if (c == '0' && stack.isEmpty()) {
continue;
}
stack.addLast(c);
}
// 最后若 k不为 0, 出栈后面的元素
while (k > 0 && !stack.isEmpty()) {
stack.pollLast();
k--;
}
// 最后将栈内元素转为字符串, 注意要反向出栈
StringBuilder sb = new StringBuilder();
while (!stack.isEmpty()) {
sb.append(stack.pollFirst());
}
return sb.length() == 0 ? "0" : sb.toString();
}
}