题目描述
思路解析动画文字版
一句话套路:逐字符压栈,每次只盯栈顶 m 个看是否等于 part,命中即弹。下面一字一字演示这条规则。
把下面这个空栈当作「结果串」。我们从左到右一个个读 s 的字符,读一个就压进栈,边压边检查栈顶。
读到第 0 个字符 "d"(流里高亮),先把它压进栈顶。
栈里还不到 3 个字符,凑不出 part,跳过检查,继续读下一个。
读到第 1 个字符 "a"(流里高亮),先把它压进栈顶。
栈里还不到 3 个字符,凑不出 part,跳过检查,继续读下一个。
读到第 2 个字符 "a"(流里高亮),先把它压进栈顶。
看栈顶最后 3 个字符:"daa"。和 part = "abc" 不相等,什么都不做,继续读下一个。
读到第 3 个字符 "b"(流里高亮),先把它压进栈顶。
看栈顶最后 3 个字符:"aab"。和 part = "abc" 不相等,什么都不做,继续读下一个。
读到第 4 个字符 "c"(流里高亮),先把它压进栈顶。
看栈顶最后 3 个字符:"abc"。正好等于 part = "abc",命中,下一帧把它们弹掉。
把栈顶这 3 个字符整段弹出,相当于在结果串里抠掉一个 part。现在暴露出新的栈顶 "a",它会接受下一个字符的检查,连锁消除就靠这一步。
读到第 5 个字符 "b"(流里高亮),先把它压进栈顶。
看栈顶最后 3 个字符:"dab"。和 part = "abc" 不相等,什么都不做,继续读下一个。
读到第 6 个字符 "a"(流里高亮),先把它压进栈顶。
看栈顶最后 3 个字符:"aba"。和 part = "abc" 不相等,什么都不做,继续读下一个。
读到第 7 个字符 "b"(流里高亮),先把它压进栈顶。
看栈顶最后 3 个字符:"bab"。和 part = "abc" 不相等,什么都不做,继续读下一个。
读到第 8 个字符 "c"(流里高亮),先把它压进栈顶。
看栈顶最后 3 个字符:"abc"。正好等于 part = "abc",命中,下一帧把它们弹掉。
把栈顶这 3 个字符整段弹出,相当于在结果串里抠掉一个 part。现在暴露出新的栈顶 "b",它会接受下一个字符的检查,连锁消除就靠这一步。
整串扫完,栈里剩下 "dab" 就是删光所有 part 后的结果。整个过程只扫一遍 s,两段 "abc" 在压栈途中分别被检测到并弹出,无需反复整串查找,这正是栈法的精髓。
边界:整串等于 part 删成空;part 不出现原样返回;重叠场景靠栈天然处理连锁。
两个高频追问:栈法对比反复 replace 的优势,以及 part 很长时的复杂度与优化方向。
参考代码
class Solution: def removeOccurrences(self, s: str, part: str) -> str: st = [] m = len(part) for ch in s: st.append(ch) if len(st) >= m and ''.join(st[-m:]) == part: del st[-m:] return ''.join(st)复杂度
- 时间:O(n·m),n 个字符各入栈一次,每次比对栈顶 m 个字符
- 空间:O(n),栈最多装下整个 s,长度 n
易错点
面试追问把动画讲成自己的话
追问和直接用 while 循环里反复 s = s.replace(part, "") 比,栈法好在哪?
追问如果 part 很长(接近 n),复杂度会怎样?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。再去主线里挑下一道练手。
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题