题目描述
思路解析动画文字版
思路一句话:高位上谁大就先删谁,删够 K 个。用栈存答案,比栈顶小且有名额就弹栈,栈从底到顶不下降。下面一步步演给你看。
上面是数字串 "1432219" 的每一位,下面这个栈用来存「保留下来的答案」,从底到顶始终保持不下降。一共可以删 3 位。
轮到第 0 位数字 '1'。栈是空的,没有更大的高位要删,直接放进去。
把 '1' 压入栈顶。此刻栈从底到顶是不下降的:1。这样高位永远不会出现「先大后小」的吃亏排列。
轮到第 1 位 '4',先看栈顶 '1':'4' 不比栈顶 '1' 小,删它不会让数变小,保留栈顶,'4' 排到后面。
把 '4' 压入栈顶。此刻栈从底到顶是不下降的:14。这样高位永远不会出现「先大后小」的吃亏排列。
轮到第 2 位 '3',先看栈顶 '4':'3' 比 '4' 小,而且还有删除名额(k=3),那留着 '4' 在高位就吃亏——把它删掉。
删掉 '4':它在更高位上却比后面的 '3' 大,删了能让数变小。已用掉 1 个名额,还剩 k=2。继续看新栈顶要不要接着删。
把 '3' 压入栈顶。此刻栈从底到顶是不下降的:13。这样高位永远不会出现「先大后小」的吃亏排列。
轮到第 3 位 '2',先看栈顶 '3':'2' 比 '3' 小,而且还有删除名额(k=2),那留着 '3' 在高位就吃亏——把它删掉。
删掉 '3':它在更高位上却比后面的 '2' 大,删了能让数变小。已用掉 1 个名额,还剩 k=1。继续看新栈顶要不要接着删。
把 '2' 压入栈顶。此刻栈从底到顶是不下降的:12。这样高位永远不会出现「先大后小」的吃亏排列。
轮到第 4 位 '2',先看栈顶 '2':'2' 不比栈顶 '2' 小,删它不会让数变小,保留栈顶,'2' 排到后面。
把 '2' 压入栈顶。此刻栈从底到顶是不下降的:122。这样高位永远不会出现「先大后小」的吃亏排列。
轮到第 5 位 '1',先看栈顶 '2':'1' 比 '2' 小,而且还有删除名额(k=1),那留着 '2' 在高位就吃亏——把它删掉。
删掉 '2':它在更高位上却比后面的 '1' 大,删了能让数变小。已用掉 1 个名额,还剩 k=0。继续看新栈顶要不要接着删。
把 '1' 压入栈顶。此刻栈从底到顶是不下降的:121。这样高位永远不会出现「先大后小」的吃亏排列。
轮到第 6 位 '9',先看栈顶 '1':'9' 不比栈顶 '1' 小,删它不会让数变小,保留栈顶,'9' 排到后面。
把 '9' 压入栈顶。此刻栈从底到顶是不下降的:1219。这样高位永远不会出现「先大后小」的吃亏排列。
别忘了最后一步:检查开头有没有前导 0(像 "0200" 要写成 "200")。这里开头是 '1',不是 0,直接就是答案。
一共删掉 3 位,剩下从底到顶就是答案 "1219"。整个过程只入栈、出栈各一次,O(n)。
空结果、前导 0、纯递增三种边界先想清。
两个高频追问,理解了就能套到「拼接最大/最小数」一类题。
参考代码
def removeKdigits(num, k): stack = [] for d in num: while k and stack and stack[-1] > d: stack.pop() # 删更大的高位 k -= 1 stack.append(d) stack = stack[:len(stack)-k] # k 有剩删尾部 return "".join(stack).lstrip("0") or "0"复杂度
- 时间:O(n),每位数字进出栈各一次
- 空间:O(n),栈最坏保留所有数字
易错点
面试追问把动画讲成自己的话
追问为什么是「单调不降」的栈,而不是不升?
追问为什么 k 有剩要从尾部删?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
132 模式
LeetCode 456 · 中等 · 沿着 栈套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题