一提到双指针,大多数人脑子里浮现的是“左右夹逼”“滑动窗口”“两数之和”这些经典模板。但 LeetCode 2105 这道题不太一样,它把双指针包装进了一个非常具体的场景:两个人站在河边,一人拎着一个水罐,从一排植物两头同时开始浇水,水不够了就得跑回河边装满再回来继续。题目问的是,整个过程中两个人一共要跑回去装水多少次。
这道题我刷完第一遍之后印象很深。它不考什么高深算法,也没有复杂的数学推导,纯粹考察你能不能把一个带有“状态”的场景稳定地翻译成代码。这种能力在面试里其实很值钱,因为很多实际需求就是这种“规则多、逻辑细、边界杂”的模拟题。如果你是刚开始刷 LeetCode,或者正在系统过一遍双指针题目,这道题值得认真做一遍,做完之后对“状态维护”和“边界处理”的理解会清晰很多。
1. 先读懂题:两个人在河边来回跑的完整过程
1.1 题目到底在描述什么场景
简化一下题目场景:河边从左到右种了一排植物,每株植物需要的浇水量存放在数组 plants 里。Alice 站在最左边,Bob 站在最右边,两个人同时出发,往中间走,每走到一株植物就用自己的水罐给它浇水。
这里有几个关键规则。
第一个规则:Alice 和 Bob 各自有一个水罐容量,也就是初始最大装水量,分别记作 capacityA 和 capacityB,一开始都是满的。每浇一株植物,水罐里的剩余水量就减少 plants[i]。
第二个规则:如果当前这株植物需要的水量比水罐里剩的水多,这个人就必须跑回河边,把水罐重新装满,再跑回来浇水。注意,这里只问“回去装水的次数”,不要求计算跑的路程。所以装水这个操作,只需要在答案上累加 1,然后把剩余水量重置成水罐容量即可。
第三个规则:Alice 和 Bob 是相对走的,一个从左往右,一个从右往左,所以他们最终会在某一株植物处相遇。相遇时,这一株植物由“剩余水量多的人”来浇;如果两个人剩余的水量恰好一样多,则规定由 Alice 来浇。
最后要求返回的是两个人重新装水的总次数。
我第一次看到这个题的时候,第一反应是“这不是很简单吗,直接模拟一遍不就行了”。但真正动手写的时候才发现,规则越简单的题目,边界情况越容易出错。尤其是相遇那一下的处理,很多人都会在这里翻车。
1.2 这道题考什么,适合谁刷
从算法分类上看,这道题属于“模拟 + 双指针”,难度在 LeetCode 上是中等偏下,但它考察的能力非常综合。
第一,它考察阅读理解能力。题面很长,但核心规则其实很少,你需要快速提取出“谁在走、什么时候装水、相遇怎么处理”这三个关键点。
第二,它考察状态维护能力。你需要同时维护 Alice 和 Bob 两个人的剩余水量,还要维护两个指针的位置,以及最后的答案计数。这四个变量在循环里是互相影响的,任何一个更新顺序错了,结果都会变。
第三,它考察边界处理能力。数组长度为 1 怎么办?两个人从出发就相遇怎么办?两个人的水都不够浇同一株植物怎么办?这些都是题目没有明说、但你必须自己处理的地方。
如果你是刚开始刷题,建议先做一下 LeetCode 2079 的“给植物浇水”,那道题是单人的版本,逻辑更简单,能帮你建立“水量不够就回去装水”的直觉。然后再做这道 2105,你会明显感觉到“从一个人变成两个人”之后,难点从“模拟”变成了“状态的同步管理”。如果你已经在备战面试,这道题可以作为模拟题的代表作反复练习,因为它几乎是面试官最爱出的“代码量大但思路简单”的题目类型。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从题意到算法:为什么双指针是显然解
2.1 单人的情况下你会怎么做
我们先退一步,不考虑 Bob,只考虑 Alice 一个人从左边开始浇完整排植物,会怎么做。
思路非常简单:用一个变量 cur 记录当前水罐里的剩余水量,遍历 plants 数组。如果 cur >= plants[i],说明水够,直接浇,cur -= plants[i]。如果 cur < plants[i],说明水不够,需要回河边装一次水,答案加 1,然后 cur = capacity,再 cur -= plants[i]。
这个过程的本质是:当前水量够不够,决定要不要触发“装水”这个动作;装完水之后,剩余水量一定要重置为初始容量,而不是在原有基础上累加。
单人版本的口诀就一句话:先判断够不够,不够就重置,再减去当前消耗。
2.2 双人场景如何变成两个指针
有了单人版的思路,双人版就顺理成章了。Alice 从左往右走,Bob 从右往左走,这不就是两个指针从两端向中间移动吗?
你只需要在单人版的基础上,把“遍历数组”改成“双指针同时移动”,并且维护两个剩余水量变量 curA 和 curB。
具体来说,在每次循环里做
