题目描述
思路解析动画文字版
记住「见 1 则 ones+1;见 0 则 flips = min(flips+1, ones)」,下面每帧都在套它。
开局两个计数都为 0。我们从左往右逐位读:见 1 累加 ones,见 0 在「翻自己」与「翻光前面的 1」之间取小。
读到第 0 位是 0,但前面一个 1 都还没有,它天然就在合法位置,不构成任何冲突。
结算:前面无 1,这个 0 不用动,flips 维持 0。
读到第 1 位是 1(紫色)。1 能不能直接留下?能——1 接在已有的 1 后面不破坏「0 在前 1 在后」的单调。
结算:这个 1 不用翻,ones 累加到 1。flips 保持 0。继续下一位。
读到第 2 位是 0(红色)。可前面已经有 1 个 1 了,0 出现在 1 后面破坏了单调,必须想办法补救。
结算:两条补救路取小——翻它自己要 1 次,翻光前面 1 个 1 要 1 次,于是 flips = 1(两者代价一样,任选其一,这里按翻当前 0 来讲)。
读到第 3 位是 1(紫色)。1 能不能直接留下?能——1 接在已有的 1 后面不破坏「0 在前 1 在后」的单调。
结算:这个 1 不用翻,ones 累加到 2。flips 保持 1。继续下一位。
读到第 4 位是 1(紫色)。1 能不能直接留下?能——1 接在已有的 1 后面不破坏「0 在前 1 在后」的单调。
结算:这个 1 不用翻,ones 累加到 3。flips 保持 1。继续下一位。
读到第 5 位是 0(红色)。可前面已经有 3 个 1 了,0 出现在 1 后面破坏了单调,必须想办法补救。
结算:两条补救路取小——翻它自己要 2 次,翻光前面 3 个 1 要 3 次,于是 flips = 2(翻当前 0 更省)。
读到第 6 位是 0(红色)。可前面已经有 3 个 1 了,0 出现在 1 后面破坏了单调,必须想办法补救。
结算:两条补救路取小——翻它自己要 3 次,翻光前面 3 个 1 要 3 次,于是 flips = 3(两者代价一样,任选其一,这里按翻当前 0 来讲)。
读到第 7 位是 0(红色)。可前面已经有 3 个 1 了,0 出现在 1 后面破坏了单调,必须想办法补救。
结算:两条补救路取小——翻它自己要 4 次,翻光前面 3 个 1 要 3 次,于是 flips = 3(翻光前面的 1 更省)。
读到第 8 位是 1(紫色)。1 能不能直接留下?能——1 接在已有的 1 后面不破坏「0 在前 1 在后」的单调。
结算:这个 1 不用翻,ones 累加到 4。flips 保持 3。继续下一位。
读到第 9 位是 1(紫色)。1 能不能直接留下?能——1 接在已有的 1 后面不破坏「0 在前 1 在后」的单调。
结算:这个 1 不用翻,ones 累加到 5。flips 保持 3。继续下一位。
读到第 10 位是 0(红色)。可前面已经有 5 个 1 了,0 出现在 1 后面破坏了单调,必须想办法补救。
结算:两条补救路取小——翻它自己要 4 次,翻光前面 5 个 1 要 5 次,于是 flips = 4(翻当前 0 更省)。
全串扫完,flips = 4 就是把 01011000110 变成单调递增所需的最少翻转次数。整个过程一遍扫描、只维护 ones 和 flips 两个数。
边界先想清:空串、全 0、全 1 都不用翻。
面试常追问 DP 本质与变体,认出「滚动变量 = 降维 DP」即可。
参考代码
class Solution: def minFlipsMonoIncr(self, s: str) -> int: ones = 0 flips = 0 for ch in s: if ch == '1': ones += 1 else: flips = min(flips + 1, ones) return flips复杂度
- 时间:O(n),扫一遍字符串
- 空间:O(1),只用 ones、flips 两个变量
易错点
面试追问把动画讲成自己的话
追问这两个变量背后其实是什么 DP?
追问如果允许结果是「若干 1 后接若干 0」呢?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
骑士拨号器
LeetCode 935 · 中等 · 沿着 动态规划套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题