链接
https://leetcode.cn/problems/remove-k-digits/description/
思路
这个题目要求移除k位后,剩下的数字最小。既然剩下的数字最小,那就牵扯到了类似于“字典序”这样一个概念。这样的题目是适合用单调栈来进行解决的。
依然是单调栈的三板斧:
1. 什么情况下我们弹栈。
2. 栈内元素是(部分)升序还是(部分)降序
3. 我们应该从前往后遍历,还是从后往前遍历
首先回答第二个问题,栈内元素应当是升序的,因为我们要求移除之后剩下的数字最小。
然后回答第三个问题,我们应该从前往后遍历。因为在一串数字中,左侧的比较大的数字对最后结果的影响最大,所以应该先处理左边。
最后回答第一个问题,我们应该遇到栈顶元素大于待入栈元素时弹栈,以保证单调栈中的元素是升序的。但这里有个k的限制,所以,当我们的k用完之前,我们可以弹栈,用完之后就不可以弹栈了。同时,如果栈顶元素是0时,我们不可以弹栈。因为0是前导0,我们在生成单调栈的过程中不需要处理。
在得到稳定的栈之后,我们还要判断k有没有用完,分别进行处理。
所以我们可以得到代码一。
但代码一并不够优雅。
第一点,我们既然要去掉k个字符,那我们就必然最多剩余remains = len(s)-k个字符。(这个是带着前导0的),这样我们就不需要在最后还去判断k的状态了。
第二点,我们在while循环中不用对0进行处理,为什么呢,因为栈顶元素大于待入栈元素,隐含了栈顶元素如果为0时不可能命中这个条件。
根据这两点可以得出代码二。
代码一
class Solution: def removeKdigits(self, num: str, k: int) -> str: single_stack = [] for i in num: # k有额度时才能弹栈 # 注意,这里用的是隐含ord比较,不需要转换成int,即可大大减少耗时 while k > 0 and single_stack and single_stack[-1] > i: # val不是0的话, 就对k进行处理 val = single_stack[-1] if val != '0': k -= 1 single_stack.pop() single_stack.append(i) res = ''.join(single_stack).lstrip('0') # k超限了, 证明需要返回0 if k >= len(res): return '0' # k没超限制, 对res进行截尾 elif k > 0: return res[:-k] return res
代码二
class Solution(object): def removeKdigits(self, num, k): stack = [] remain = len(num) - k for digit in num: while k and stack and stack[-1] > digit: stack.pop() k -= 1 stack.append(digit) return ''.join(stack[:remain]).lstrip('0') or '0'
标签:弹栈,数字,res,元素,single,num,402,移掉,stack From: https://www.cnblogs.com/bjfu-vth/p/17748473.html