<p>动态规划解法通过预处理左右最高墙高度数组,使每个位置接水量为min(left_max[i], right_max[i]) - height[i](结果>0);双指针法用两个变量边走边维护边界最大值,依据短板效应移动指针。</p>

动态规划解法:预处理左右最高墙高度
核心是避免对每个位置都暴力扫描,用两个数组提前存好 left_max[i] 和 right_max[i]:即下标 i 左侧(含自身)最高柱子高度、右侧(含自身)最高柱子高度。这样每个位置能接的水量就是 min(left_max[i], right_max[i]) - height[i],前提是结果大于 0。
注意点:
-
left_max[0] = height[0],之后从左到右递推:left_max[i] = max(left_max[i-1], height[i]) -
right_max[n-1] = height[n-1],之后从右到左递推:right_max[i] = max(right_max[i+1], height[i]) - 空间复杂度 O(n),时间复杂度 O(n);若只用两个变量滚动更新,可优化为 O(1) 空间,但那就不是标准 DP 了
双指针解法:边走边维护左右边界最大值
本质是动态规划的空间优化——不存整个数组,只用 left_max 和 right_max 两个变量,并利用「短板效应」决定移动哪边指针。关键判断逻辑是:当前能接多少水,取决于较矮那边已知的最大值。
操作步骤:
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 初始化
left = 0,right = n-1,left_max = 0,right_max = 0,ans = 0 - 当
left 时循环:<br> 若 <code>height[left] ,说明左边柱子矮,<code>left_max决定当前容量 → 更新left_max = max(left_max, height[left]),再累加max(0, left_max - height[left]),然后left++
否则右边矮,同理处理right - 必须先更新
left_max/right_max,再计算积水,否则会把当前柱子高度误当作“墙”参与减法
为什么双指针里不能直接用 min(left_max, right_max) 减?
因为 left_max 和 right_max 并非严格对应「当前位置左侧最大」和「右侧最大」——它们只是截至目前遍历过的最大值。但双指针正确性依赖一个事实:当 height[left] 时,<code>left_max 必然 ≤ right_max,且 left_max 就是 left 位置真正的左侧最高墙(因右边还没扫完,但左边已确定),而真正限制水量的是这个更小的 left_max。反过来说,如果强行用 min(left_max, right_max),在某次 height[left] 很高但 right_max 还很小的时候,会低估可接水量。
常见错误现象:
• 没有先更新 left_max 就直接算 left_max - height[left] → 可能得出负数或漏算
• 移动指针条件写成 height[left] 却没处理相等情况的逻辑一致性 → 边界 case 如全相同高度时结果偏小
实际编码时最容易被忽略的细节
双指针法中,left_max 和 right_max 的初值必须设为 0,而不是 height[0] 和 height[n-1]。因为一开始还没访问任何柱子,最大值确实是 0;等第一次进入循环后,才通过 max(0, height[left]) 把第一个值纳入。否则在单元素输入如 [1] 时,会错误地认为能接 1 单位水。
动态规划若用 vector 存两数组,记得检查 height 是否为空,否则 left_max[0] 访问越界。双指针则天然兼容空输入(left 不成立直接跳过)。

















