题目描述
思路解析动画文字版
最直接是枚举每个起点,从它出发模拟跑一圈、看油箱会不会变负。n 个起点、每个跑 n 步,O(n²)。其实一次失败能透露很多信息,不必每个起点从头再试。
关键招:若 sum(net) 小于 0,怎么都跑不完,返回 −1。否则从 0 出发累加 net,一旦油箱 tank 变负,说明从当前起点到这里这一整段都当不了起点——因为这段里油箱一直 ≥0,去掉它前面任意一站当起点只会油更少、更到不了这里。所以起点直接跳到 i+1、tank 清零。一遍扫描即可,这就是它 O(n) 的原因。
先看总量:先算 net 总和:等于 0,≥ 0,说明存在可行起点。接下来一遍扫描把它找出来。
起点就位:油箱 tank 清零,候选起点 start=0(紫 l 标起点)。开始累加 net。
i=0 · 油箱变负 → 起点跳到 1:负例分支:从 0 出发,tank = −2 小于 0,抛锚。0 当不了起点,把 start 跳到 1、tank 清零重新算。
i=1 · 又变负 → 起点跳到 2:从 1 出发也立刻 tank = −2 小于 0,start 跳到 2。下标 0 已被整段排除(变灰)。
i=2 · 还是负 → 起点跳到 3:从 2 出发仍是 tank = −2,start 跳到 3。前三站 [0,1,2] 整段都被排除了。
i=3 · 油箱 +3 → 撑住:从 3 出发,tank = 3 ≥ 0,没抛锚,start 保持 3,继续往后开。
i=4 · 油箱 +6 → 顺利:再往后 tank = 6 ≥ 0,从 start=3 起油箱一路没变负。扫描到末尾结束。
结果:因为总油 ≥ 总耗(第一步已确认有解),扫描结束时留下的起点 3 就是唯一可行出发站。
不傻试每个起点,而是利用「跑到这里就变负」这条失败信息,一次性跳过整段不可能的起点——这就是贪心的剪枝,把 O(n²) 暴力降到 O(n)。
边界三连:三种边界先想清楚。
面试官常追问:三个高频追问,答法记牢。
参考代码
class Solution: def canCompleteCircuit(self, gas, cost): total = tank = start = 0 for i in range(len(gas)): net = gas[i] - cost[i] total += net tank += net if tank < 0: # 从 start 跑不到 i+1 start = i + 1 # 起点跳到 i+1 tank = 0 return start if total >= 0 else -1 # 总净油≥0 才有解复杂度
- 时间复杂度:O(n),一遍扫描:total 累计净油判可行、tank 同时定起点,只走一趟,线性
- 空间复杂度:O(1),只用 tank、start 两个变量
可套用的代码模板
骨架就是「全局量判可行 + 局部量变负就重置」。最大子数组和(LC53)只把 run 换成「当前最大和」、start 换成记录答案,几乎一模一样。
Python
# 一遍扫描里「局部累计变负就丢弃重来」的通用骨架total, run, start = 0, 0, 0for i in range(n): total += val[i] # 全局量:判可行 / 求总和 run += val[i] # 局部量:当前这一段 if run < 0: # 这一段废了 run, start = 0, i + 1 # 清零,起点跳到下一站易错点
面试追问把动画讲成自己的话
追问核心思路是什么?
追问为什么这样贪心是对的?
追问复杂度多少?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
一手顺子
LeetCode 846 · 中等 · 沿着 贪心 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题