双指针法能正确计算接雨水是因为:当leftmax ≤ rightmax时,位置l的水位上限已被leftmax“夹死”,后续右侧更大值不影响当前结果,故可立即结算l处水量并更新leftmax后左移;反之同理处理右侧,从而在o(1)空间内边遍历边确定每处水量。

双指针法是解决接雨水问题最省空间的方案,trap 函数能用 O(1) 额外空间、O(n) 时间完成,关键不在“两个指针”,而在于“哪边矮,就先算哪边”这个判断逻辑。
为什么双指针能避免预处理 leftMax/rightMax 数组
动态规划需要两个长度为 n 的数组存左右最大值,但实际每次只用到 min(leftMax[i], rightMax[i]) —— 真正决定水量的是那个更小的值。只要保证「当前矮侧的 max 值确实是它那一侧全局最大」,就能安全计算该侧位置的水量。
- 当
pleft 时,左指针位置的水量一定由 <code>pleft决定,因为右指针还没扫完,pright可能还会变大,但pleft已经是左边所有值里的最大值,且它比当前已知的右最大还小,所以min必然是pleft - 同理,
pleft >= pright时,右指针位置的水量由pright决定 - 因此不需要提前算完整数组,边走边更新即可
双指针移动时 max 更新和水量计算的顺序不能错
常见错误是先移动指针再更新 max,或把加水量写在更新 max 之前。正确顺序必须是:先用当前指针值更新对应侧 max,再比较两侧 max,最后计算并累加水量,然后才移动指针。
- 错误写法:
sum += pleft - height[left]; left++; pleft = max(pleft, height[left]);—— 移动后取的是新位置的 height,但 max 更新晚了一步,pleft没覆盖当前位置 - 正确写法:先
pleft = max(pleft, height[left]),再sum += pleft - height[left],最后left++ - 边界位置(
left == 0或right == n-1)天然不会积水,公式中min(...) - height[i]会自然得负数 → 取 0,但双指针法里靠pleft/pright初始为 0 和更新时机已隐式处理了这点
初始值设为 0 是安全的,但空输入必须提前检查
pleft 和 pright 初始化为 0 没问题,因为 height[i] >= 0,第一次更新 max(0, height[...]) 就能得到真实高度。但若输入 height 为空或只有一个元素,while (left 不会进循环,直接返回 0 —— 这符合题意(无法形成凹槽),但最好显式判空,避免后续访问越界。
- 加一句
if (height.empty()) return 0;更稳妥 - 不要用
height.size() == 0判断,empty()语义更清晰 - 如果用
vector<int>::size_type</int>做索引,注意size()返回无符号类型,size() - 1在空 vector 下会回绕成极大值,导致right初始化出错
真正容易被忽略的不是“怎么写”,而是“为什么移动矮侧就一定安全”——它依赖于:矮侧的 max 已确定,且另一侧的 max 至少不比它小,所以 min 就是它;一旦算完,这个位置就不再参与后续决策,可以放心移走。这个洞察一旦卡住,代码就容易写成“看起来像双指针,实则逻辑错位”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











