题目描述
思路解析
一句话答案:LeetCode 2079 给植物浇水:水罐从 x=-1 河边出发按序浇,余量够就前进 1 步浇、不够先退回河接满再来,一遍模拟累加步数,时间 O(n)、空间 O(1)。
这一排植物,要数的是浇完一共走的步数
n 株植物排成一行,第 i 株站在坐标 x = i,要浇 plants[i] 单位水。你提水罐从 x = -1 河边出发,容量 capacity 且初始装满,从左到右挨个浇。浇完一株若剩水不足以灌满下一株,就得先退回河边接满再来,不许提前补水。x 轴挪一格算一步,问浇完共走多少步。例子 plants=[2,2,3,3]、capacity=5,答案 14 步。
要不要把各种浇法都试一遍
浇水顺序被题目钉死,从左往右一株接一株,没有先浇谁后浇谁的选择。所以用不上回溯或搜索——每一株怎么处理,只看走到它跟前时水罐还剩多少:够就浇、不够就回河。从头扫一遍、边走边加步数就是答案,时间 O(n)。
回河一趟,为什么偏偏是 2 乘 i 加 1 步
浇每一株先拿水罐余量和需水量比。余量够,即大于等于需水量,从上一株迈 1 步踩到这株浇掉,步数加 1、余量减需水。余量不够就回河:此刻人站在植物 i 减 1 处,即 x = i 减 1,先后退 i 步回到 x = -1 河边接满,再前进 i 加 1 步走到植物 i。后退 i 步加前进 i 加 1 步,正好 2 乘 i 加 1 步,浇完余量重置成 capacity 减需水。
一趟模拟怎么一株株走下来
模拟就是照规则一步步走一遍。water 记余量、初始等于 capacity,ans 记步数、从 0 开始。从下标 0 扫到最后一株,每株判一次 water 够不够当前需水:够就 ans 加 1、water 减需水;不够就 ans 加上 2 乘 i 加 1、water 重置成 capacity 减需水。扫完 ans 就是总步数。
[2,2,3,3]、容量 5,一路走多少步
water=5、ans=0 起步。植物 0 要 2,5 大于等于 2 够浇,前进 1 步,water 剩 3、ans=1。植物 1 要 2,3 够浇,再前进 1 步,water 剩 1、ans=2。植物 2 要 3,water 只剩 1 不够:人在 x=1,后退 2 步回河接满、前进 3 步到植物 2,2 乘 2 加 1 等于 5 步,ans 从 2 跳到 7,water 变 5 减 3 等于 2。植物 3 要 3,water 剩 2 又不够:人在 x=2,后退 3 步回河、前进 4 步,2 乘 3 加 1 等于 7 步,ans 从 7 跳到 14。共 14 步,对上题面。
回河那一步最容易漏,一漏整数就少一大截
几处稍不留神就算偏。起点是 x = -1 不是 x = 0,从河边到植物 0 得算 1 步,当成 0 步就少了。判够不够要用大于等于,余量正好等于需水量时能浇满、不必白跑,写成严格大于会凭空多折返一趟。回河步数是完整的 2 乘 i 加 1,只记 i 步或 i 加 1 步都偏小,折返本就是一退一回两段路。
复杂度上只扫一遍、每株做常数次比较和加减,时间 O(n);只用 ans 和 water 两个整数,空间 O(1)。最坏时除第一株外几乎每株都回河,步数约 n 平方量级,n 最大 1000 即百万级,32 位整数装得下。
▶ 动画逐步走查(文字版)——想跟着上方动画一帧帧对照就展开
记牢这套口诀:够浇就前进 1 步、余量减需求;不够就回河一趟加 2 乘 i 加 1 步、余量重置成 capacity 减需求。下面每一帧都在套它。
先认识花园。舞台这一排就是 7 株植物,从左到右下标 0 到 6,格子里的数字是它各自的需水量,比如植物 0 要 2 单位、植物 2 要 5 单位。它们站的位置正好等于下标,植物 3 就在 x = 3。水罐容量是 6,画面左边看不见的 x = -1 处有条河,专门用来灌满水罐。
出发。人现在在 x = -1 的河边,把水罐灌满,water = 6,已走步数 ans = 0。紫色指针指向植物 0,就是我们第一个要去浇的目标。注意从河边走到植物 0 本身也要花 1 步,这一步等下浇的时候一起算。
轮到植物 0,它需要 2 单位水。关键动作:拿水罐当前余量 6 和它的需水 2 比一比。余量 6 大于等于 2,够浇,不用回河。
够浇,直接动手。从上一株的位置往前走 1 步踏到植物 0,把它浇了,水罐余量从 6 减去 2 剩 4。步数只加这 1 步,ans 变成 1。植物 0 变绿,表示浇好了。
轮到植物 1,它需要 4 单位水。左边蓝色的是已经浇好的植物。关键动作:拿水罐当前余量 4 和它的需水 4 比一比。余量 4 大于等于 4,够浇,不用回河。
够浇,直接动手。从上一株的位置往前走 1 步踏到植物 1,把它浇了,水罐余量从 4 减去 4 剩 0。步数只加这 1 步,ans 变成 2。植物 1 变绿,表示浇好了。
轮到植物 2,它需要 5 单位水。左边蓝色的是已经浇好的植物。关键动作:拿水罐当前余量 0 和它的需水 5 比一比。余量 0 比 5 还小,不够完全浇灌,这一趟得先回河边。
水不够,先回河边。此刻人站在植物 1 那里,也就是 x = 1,一路后退到 x = -1 的河边,要走 2 步。到了河边把水罐重新灌满,water 回到 6。步数先记上这后退的 2 步,ans 暂时是 4。植物 2 标红,提醒它就是那株让我们折返的。
灌满后再从河边走回来。从 x = -1 走到植物 2 要走 3 步,踏上去把它浇了。这一整趟折返合计 2 加 3 等于 5 步,正好是 2 乘 2 加 1。ans 一下子跳到 7,水罐余量变成 6 减 5 等于 1。植物 2 浇好变绿。
轮到植物 3,它需要 1 单位水。左边蓝色的是已经浇好的植物。关键动作:拿水罐当前余量 1 和它的需水 1 比一比。余量 1 大于等于 1,够浇,不用回河。
够浇,直接动手。从上一株的位置往前走 1 步踏到植物 3,把它浇了,水罐余量从 1 减去 1 剩 0。步数只加这 1 步,ans 变成 8。植物 3 变绿,表示浇好了。
轮到植物 4,它需要 2 单位水。左边蓝色的是已经浇好的植物。关键动作:拿水罐当前余量 0 和它的需水 2 比一比。余量 0 比 2 还小,不够完全浇灌,这一趟得先回河边。
水不够,先回河边。此刻人站在植物 3 那里,也就是 x = 3,一路后退到 x = -1 的河边,要走 4 步。到了河边把水罐重新灌满,water 回到 6。步数先记上这后退的 4 步,ans 暂时是 12。植物 4 标红,提醒它就是那株让我们折返的。
灌满后再从河边走回来。从 x = -1 走到植物 4 要走 5 步,踏上去把它浇了。这一整趟折返合计 4 加 5 等于 9 步,正好是 2 乘 4 加 1。ans 一下子跳到 17,水罐余量变成 6 减 2 等于 4。植物 4 浇好变绿。
轮到植物 5,它需要 5 单位水。左边蓝色的是已经浇好的植物。关键动作:拿水罐当前余量 4 和它的需水 5 比一比。余量 4 比 5 还小,不够完全浇灌,这一趟得先回河边。
水不够,先回河边。此刻人站在植物 4 那里,也就是 x = 4,一路后退到 x = -1 的河边,要走 5 步。到了河边把水罐重新灌满,water 回到 6。步数先记上这后退的 5 步,ans 暂时是 22。植物 5 标红,提醒它就是那株让我们折返的。
灌满后再从河边走回来。从 x = -1 走到植物 5 要走 6 步,踏上去把它浇了。这一整趟折返合计 5 加 6 等于 11 步,正好是 2 乘 5 加 1。ans 一下子跳到 28,水罐余量变成 6 减 5 等于 1。植物 5 浇好变绿。
轮到植物 6,它需要 4 单位水。左边蓝色的是已经浇好的植物。关键动作:拿水罐当前余量 1 和它的需水 4 比一比。余量 1 比 4 还小,不够完全浇灌,这一趟得先回河边。
水不够,先回河边。此刻人站在植物 5 那里,也就是 x = 5,一路后退到 x = -1 的河边,要走 6 步。到了河边把水罐重新灌满,water 回到 6。步数先记上这后退的 6 步,ans 暂时是 34。植物 6 标红,提醒它就是那株让我们折返的。
灌满后再从河边走回来。从 x = -1 走到植物 6 要走 7 步,踏上去把它浇了。这一整趟折返合计 6 加 7 等于 13 步,正好是 2 乘 6 加 1。ans 一下子跳到 41,水罐余量变成 6 减 4 等于 2。植物 6 浇好变绿。
七株植物全部浇完。回看一路:植物 0、1、3 是余量够、直接前进 1 步浇的;植物 2、4、5、6 都是余量不够、回河折返浇的,越往右回一趟越贵,因为后退和前进的距离都变长了。把每一步累加起来,总共走了 41 步,这就是答案。
边界想清:单株正好够是 1 步、每次余量不足就回河一趟、极端情况除第一株外几乎每株都回河。
面试重点:顺序固定所以一遍模拟、回河一趟是 2 乘 i 加 1 步、步数是 n 平方量级 int 够用。
参考代码
from __future__ import annotationsfrom typing import *from collections import *from functools import *from itertools import *from math import *from heapq import *from bisect import *class Solution: def wateringPlants(self, plants: List[int], capacity: int) -> int: ans, water = 0, capacity for i, p in enumerate(plants): if water >= p: water -= p ans += 1 else: water = capacity - p ans += i * 2 + 1 return ans复杂度
- 时间:O(n),n 株植物,从左到右只扫一遍,每株做的都是常数次比较和加减,没有嵌套循环,总量随植物数线性增长
- 空间:O(1),只用 ans 和 water 两个整数变量,不随植物数量增长而多占空间,输入数组本身不算额外开销
易错点
面试追问把动画讲成自己的话
追问这题为什么一遍遍历就够,不用回溯或搜索?
追问回河一趟的步数公式 2 乘 i 加 1 是怎么来的?
追问步数会不会超出 int 范围?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
执行所有后缀指令
LeetCode 2120 · 中等 · 沿着 数组套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题