题目描述
思路解析
一句话答案:LeetCode 134 加油站:环形站里求能绕一圈的出发点,贪心一遍扫描——总净油量非负才有解,累加途中油箱一跌成负数就把起点跳到下一站、清零重攒,时间 O(n)、空间 O(1)。
环形加油站,求哪个站能发车绕一圈
n 个加油站围成一圈,第 i 站能加 gas[i] 升油,从第 i 站开到下一站耗 cost[i] 升,油箱起初为空。挑一个站作起点绕一圈,绕回原点就返回它下标,绕不完返回 -1。题面 gas=[4,5,2,6,1,3,7,2,5,4,8,3]、cost=[6,3,5,2,7,2,1,8,3,2,4,6],答案是下标 5。
每个站都试一次当起点,慢在哪
把每个站轮流当起点、模拟开一圈,中途油箱不跌到负就算能绕完。12 个站要试 12 趟、每趟走满一圈,n 个站是 n×n 次操作、也就是 O(n²)。很多起点刚开出去就断油,却还陪着走完才判出局。
总量定生死,跌负点之后才是真起点
先算每站的净油量 net[i]=gas[i]−cost[i]。全部加起来是总净油量,它若为负,说明全程油不够耗、哪都开不完,直接 -1;本题总净油量 +1、非负,可行起点一定存在。
有解后再定它落哪。从某个起点累加 net,油箱非负就往下走;一旦某站油箱跌成负数,说明这个起点到当前站整体是亏的。这中间每一站也当不了起点:从中途某站另起,等于丢掉前面那段净油——那段没让油箱提前跌负、必然非负,丢掉只会更早断油。所以这一段起点全排除,候选直跳到跌负站后一位、清零重攒,起点只前移不回退。
三个变量,一遍扫完就定起点
落到代码就三个变量:total 累加全程净油量、只用来判有无解;tank 是当前起点出发后的油箱;start 记候选起点、从 0 起。遍历每站,total 和 tank 都加这站的 net,一旦 tank 跌成负数,就让 start 跳到 i+1、tank 归零。扫完一趟,total≥0 就返回 start,否则 -1。
题面这 12 个站,start 怎样被逼到 5
净油量依次 −2、+2、−3、+4、−6、+1、+6、−6、+2、+2、+4、−3,加起来 +1、有解。start=0、tank=0 开扫。站 0 加 −2 得 −2 跌负,start 跳到 1、清零。站 1 加 +2 得 2。站 2 加 −3 得 −1 又跌负,start 跳到 3、清零。站 3 加 +4 得 4。站 4 加 −6 得 −2 第三次跌负,start 跳到 5、清零。
从站 5 起没再跌过:站 5 加 +1 得 1,站 6 加 +6 得 7,站 7 加 −6 得 1,站 8 加 +2 得 3,站 9 加 +2 得 5,站 10 加 +4 得 9,站 11 加 −3 得 6。start 停在 5,total 也累到 +1、非负,返回下标 5。
起点是跳不是挪,别踩这几个坑
最坑的是把跳转当逐格挪:tank 跌负时只让 start 挪一格,等于没吸取 start..i 整段都不可行、白试几趟还停在错起点,得一步跳到 i+1。跳完忘清 tank,新起点会背着上段亏账越加越偏。还有拿 tank 判有没有解也错——它被清过零、只反映当前段,得看累到尾的 total。
复杂度上,只从左到右扫一趟、每站常数次运算,时间 O(n),把暴力那圈套圈的 O(n²) 压平;只用三变量,空间 O(1)。
▶ 动画逐步走查(文字版)——想跟着上方动画一帧帧对照就展开
记住这句「一旦从某起点走到某站油箱为负,这之间任何站都当不了起点,起点跳到下一站重新攒」——下面每一帧都在套它。我们把每站的净油量画成一条数轴来扫。
把每站的净油量 net[i]=gas[i]−cost[i] 摆成一排(这就是动画主体,不是加油量本身)。总净油量是 +1,≥0 所以保证有解。绿色高亮的是当前候选起点 start=0,油箱 tank 从 0 开始。
第 1 步:扫到站 0,它的净油量是 -2。把它累加到油箱:tank = 0 -2 = -2。注意——加完油箱变负了,下一帧要处理起点跳转。
油箱变负了!说明从起点 0 一路开到站 0,中途必然在某处断油。关键:0 到 0 之间任何一站都当不了起点(从更靠后出发,少攒了前面的油,只会更早断),所以一次性把它们全排除(灰掉),起点直接跳到下一站 1,tank 归零从头攒。
第 2 步:扫到站 1,它的净油量是 +2。把它累加到油箱:tank = 0 +2 = 2。油箱还没见底,候选起点暂时不变。
油箱 tank=2,还是非负的,说明从起点 1 出发到站 1 一路没断油,这个候选起点先留着,继续往右扫下一站。
第 3 步:扫到站 2,它的净油量是 -3。把它累加到油箱:tank = 2 -3 = -1。注意——加完油箱变负了,下一帧要处理起点跳转。
油箱变负了!说明从起点 1 一路开到站 2,中途必然在某处断油。关键:1 到 2 之间任何一站都当不了起点(从更靠后出发,少攒了前面的油,只会更早断),所以一次性把它们全排除(灰掉),起点直接跳到下一站 3,tank 归零从头攒。
第 4 步:扫到站 3,它的净油量是 +4。把它累加到油箱:tank = 0 +4 = 4。油箱还没见底,候选起点暂时不变。
油箱 tank=4,还是非负的,说明从起点 3 出发到站 3 一路没断油,这个候选起点先留着,继续往右扫下一站。
第 5 步:扫到站 4,它的净油量是 -6。把它累加到油箱:tank = 4 -6 = -2。注意——加完油箱变负了,下一帧要处理起点跳转。
油箱变负了!说明从起点 3 一路开到站 4,中途必然在某处断油。关键:3 到 4 之间任何一站都当不了起点(从更靠后出发,少攒了前面的油,只会更早断),所以一次性把它们全排除(灰掉),起点直接跳到下一站 5,tank 归零从头攒。
第 6 步:扫到站 5,它的净油量是 +1。把它累加到油箱:tank = 0 +1 = 1。油箱还没见底,候选起点暂时不变。
油箱 tank=1,还是非负的,说明从起点 5 出发到站 5 一路没断油,这个候选起点先留着,继续往右扫下一站。
第 7 步:扫到站 6,它的净油量是 +6。把它累加到油箱:tank = 1 +6 = 7。油箱还没见底,候选起点暂时不变。
油箱 tank=7,还是非负的,说明从起点 5 出发到站 6 一路没断油,这个候选起点先留着,继续往右扫下一站。
第 8 步:扫到站 7,它的净油量是 -6。把它累加到油箱:tank = 7 -6 = 1。油箱还没见底,候选起点暂时不变。
油箱 tank=1,还是非负的,说明从起点 5 出发到站 7 一路没断油,这个候选起点先留着,继续往右扫下一站。
第 9 步:扫到站 8,它的净油量是 +2。把它累加到油箱:tank = 1 +2 = 3。油箱还没见底,候选起点暂时不变。
油箱 tank=3,还是非负的,说明从起点 5 出发到站 8 一路没断油,这个候选起点先留着,继续往右扫下一站。
第 10 步:扫到站 9,它的净油量是 +2。把它累加到油箱:tank = 3 +2 = 5。油箱还没见底,候选起点暂时不变。
油箱 tank=5,还是非负的,说明从起点 5 出发到站 9 一路没断油,这个候选起点先留着,继续往右扫下一站。
第 11 步:扫到站 10,它的净油量是 +4。把它累加到油箱:tank = 5 +4 = 9。油箱还没见底,候选起点暂时不变。
油箱 tank=9,还是非负的,说明从起点 5 出发到站 10 一路没断油,这个候选起点先留着,继续往右扫下一站。
第 12 步:扫到站 11,它的净油量是 -3。把它累加到油箱:tank = 9 -3 = 6。油箱还没见底,候选起点暂时不变。
油箱 tank=6,还是非负的,说明从起点 5 出发到站 11 一路没断油,这个候选起点先留着,继续往右扫下一站。
一整趟扫描下来,前面那些会让油箱断油的起点都被一次次跳过排除,最后稳稳留下的 start=5 就是答案。因为总净油量 +1≥0,从它出发保证能绕完一圈。绿色高亮的就是最终出发站。
边界先想清:总净油量为负一律 -1;只要 total≥0,本算法一定能定出一个可行起点。
两个高频追问:有无解只看 total 一个数;留下的 start 可行性由「前面全不可行 + total≥0 必有解」两点夹出来。
参考代码
def canCompleteCircuit(gas, cost): total = 0 # 总净油量,判有没有解 tank = 0 # 当前候选起点出发后的油箱 start = 0 # 当前候选起点 for i in range(len(gas)): net = gas[i] - cost[i] # 这站净油量 total += net tank += net if tank < 0: # 油箱见底 start = i + 1 # 起点跳到下一站 tank = 0 # 清零重新攒 return start if total >= 0 else -1复杂度
- 时间:O(n),只扫一遍 n 个站,每站常数时间累加与判断
- 空间:O(1),只用 total / tank / start 三个变量
易错点
面试追问把动画讲成自己的话
追问怎么先一步判断到底有没有解?
追问为什么贪心扫一遍留下的 start 一定可行,不会漏掉前面更好的起点?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
一手顺子
LeetCode 846 · 中等 · 沿着 贪心 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题