402. 移掉K位数字
题目来源:力扣(LeetCode)https://leetcode-cn.com/problems/remove-k-digits/
题目
给定一个以字符串表示的非负整数 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。
解题思路
思路:单调栈
先审题,题目给定一个由字符串表示的非负整数 num
,要求移除 k
位数字,使得剩下的数字最小。
其中提及需注意的点如下:
num
不含前导零;num
的长度小于10002
且大于等于k
。
那么现在的问题就是,如何确定移除的数字,使得剩余数字最小?
先说下数字比较的问题。当比较非负整数大小时,在不含前导零的情况下,且数字位数相同时,我们需要逐位对比数字的大小,然后确定整体数字的大小。例如:
# 比较相同位数的 123 和 132
123
132
首位 1
相同,但第二位中 132
的 3
大于 123
中的 2
,所以 132 > 123
。
也即是说,当两个数字位数相同(两数不等)的情况下,由高位决定大小。
回到本题,现在我们要考虑移除 k
位数字,要想最终得到数字最小,那么我们应该从移除高位较大的数字,保留较小的数字。以示例 1 来进行说明:
输入: num = "1432219", k = 3
输出: "1219"
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。
这里 k
为 3
,需要移除 3
位数字。这里说明下移除 1
位的情况(因为后续的情况思路也是相同的)。
在前面的分析中我们可知,两个数字位数相同(两数不等)的情况,高位决定大小。例子中 "1432219"
,我们可以移除任意一个数字,而得到的剩余数字的位数都是相同的。在这里,输出中先将 4
移除,保留剩下的数字,即是优先移除高位较大的数字。
题目中给定的数字是以字符串表示的,那么假设我们将数字用列表的形式表示,现在我们要找高位较大的数字时,做法如下:
从左到右遍历列表,当找到 i ( i > 0 ) i(i > 0) i(i>0),使得 n u m [ i − 1 ] > n u m [ i ] num[i-1] > num[i] num[i−1]>num[i],那么这里我们就可以确定,在这个区间中 n u m [ i − 1 ] num[i-1] num[i−1] 是较大的数字,考虑将其移除。若还需继续移除数字,以同样的做法进行。
这里需要注意,若无法找到 i i i 满足上面的条件时,则表示这个序列是(不严格的)单调递增的,那么可以从序列后面开始移除。
这里不严格的单调递增,表示序列数字可能存在相等的情况。
单调栈
在这里,我们可以考虑使用单调栈的思路来实现上面的策略。
具体的思路如下:
- 定义栈,从左往右开始遍历字符串;
- 进行比较,如果遍历的数字小于栈顶的元素,那么进行出栈。
- 当满足以下条件时,停止出栈:
- 出栈元素的次数达到 k 次;
- 栈为空;
- 栈顶元素不再大于遍历的数字。
- 若不满足上面的条件时,继续入栈直至遍历结束。
当遍历结束后,这里还需要注意一些问题:
- 当出栈的数字个数小于
k
时,也即是移除的数字个数不够时,由于此时的栈是单调不减的,那么直接从尾部移除剩下的数字; - 如果剩余数字存在前导零的情况时,我们要将前导零删除;
- 如果最终数字为空时,返回字符串
'0'
。
具体代码实现如下。
class Solution:
def removeKdigits(self, num: str, k: int) -> str:
# 定义栈
stack = []
# 开始遍历
for digit in num:
# 数组 num 的长度一定是大于或等于 k 的
# 如果栈顶数字大于遍历数字时,出栈
while k > 0 and stack and stack[-1] > digit:
stack.pop()
k -= 1
# 否则入栈
stack.append(digit)
# 若此时栈为单调递增栈,但是还未移除完 k 位数字
# 直接从栈顶移除数字,这里 python 直接用列表切片
ans = stack[:-k] if k > 0 else stack
# 注意前导 0 的情况
return ''.join(ans).lstrip('0') or '0'
欢迎关注
公众号 【书所集录】
如有错误,烦请指出,欢迎指点交流。