LeetCode 移掉K位数字(402题)
@author:Jingdai
@date:2020.10.24
题目描述(402题)
给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。
注意
num 的长度 ≥ k num 不会包含任何前导零
示例输入
num = "1432219", k = 3
示例输出
"1219"
解释
移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。
思路
题目要求是移除 k 位数字,所以最后剩下的数字的长度是一定的,即为
num.length() - k
,所以我们可以直接考虑对于长度固定的子数的最小值是多少。而对于一个固定长度的数来说,数的大小取决于第一个不一样的数,如
123axyz
和123bznz
的大小取决于a
和b
的大小,当a > b
时,123axyz
>123bznz
,反之亦然。所以我们应该从左往右遍历,对于每个数字考虑舍弃还是保留。那怎么确定一个数是保留还是舍弃呢?将这个数和之前那个数进行比较,如果这个数比之前那个数小,就将之前的那个数舍弃,如果之前的数仍然大于当前数,则继续舍弃。看下面的栗子就懂了。
对于示例中的
"1432219"
,首先第一个数1
没有和它比较的数,所以直接过。然后第二个数如图,4 > 1
,所以选择保留1
,这里其实就是比较1
和4
。如图,对于第三个数
3
,3 < 4
,所以选择去掉4
,这里其实是比较14
和13
哪个更小,显然13
更小,然后就把4
去掉了。然后继续比较1
和3
,3 > 1
所以保留1
。然后继续下一个数2
…直到删除k个数字。但是这样会漏掉一种情况,就是可能遍历完也没有删除完 k 个数字,比如对于数
"123456"
这样的数,删除3
个数,显然按照刚才的方法遍历完也是 6 位,对于这种情况,可以直接截取剩下数的前num.length() - k
位即可。同时,会发现这个题目很容易用 stack 来实现,每次比较栈顶元素和当前元素,
pop
出比当前数字大的元素,然后push
当前数字。代码如下。
代码
public static String removeKdigits(String num, int k) { if (num.length() == 0) { throw new RuntimeException("Wrong Num!"); } LinkedList<Character> stack = new LinkedList<>(); int tempK = k; for (int i = 0; i < num.length(); i++) { while (tempK > 0 && stack.size() != 0 && num.charAt(i) < stack.peek()) { tempK--; stack.pop(); } stack.push(num.charAt(i)); } StringBuilder sb = new StringBuilder(); boolean isHeadingZero = true; for (int i = 0; i < num.length() - k; i++) { Character tempNumber = stack.removeLast(); if (isHeadingZero && tempNumber == '0') { continue; } isHeadingZero = false; sb.append(tempNumber); } return sb.length() == 0 ? "0" : sb.toString(); }