困难LeetCode 42可逐步演示引导学习
接雨水
双指针:每一格能接多少水
用左右两个指针维护两侧见过的最大高度;每一格的水量由较矮一侧的最大值决定,算出当前格水量后向中间收缩。
时间复杂度 O(n)空间复杂度 O(1)
题单:面试热题
题目描述
给定一个非负整数数组 height,每个元素表示宽度为 1 的柱子的高度。下雨后,柱子之间能接住多少单位的雨水?
学习目标
能推导每一格水量的公式,理解为什么可以只移动较矮的一侧,并写出 O(1) 空间的双指针实现。
已完成 0 / 6 阶段
诊断
先写出每一格的水量
位置 i 能接多少水?它由左边最高柱子和右边最高柱子中的哪一个决定?
位置 i 的水量公式是?
建议先完成当前阶段(提示 / 检查 / 自评),再进入下一步;也可以直接跳过。
解题思路
核心思想
用左右两个指针维护两侧见过的最大高度;每一格的水量由较矮一侧的最大值决定,算出当前格水量后向中间收缩。
为什么需要它
暴力对每一格分别向左、向右找最高柱子,是 O(n²)。如果预先存下每个位置左右最高柱子,可以做到 O(n),但要两个数组;双指针把这两个数组压缩成两个变量,空间降到 O(1)。
第一反应:直觉方案
对每个位置 i,水量 = min(左边最高, 右边最高) - height[i](结果不能为负)。按这个定义逐格计算最直接,但每次都要向两边扫描。
关键洞察
关键洞察:如果左边的最高柱子比右边低,那么当前左指针这一格的水面高度只由左边最高决定,右边无论多高都限制不了它。于是可以放心结算左边这一格,再把左指针右移;右边对称。这样每个位置只处理一次,且不需要预先存两边最大值。
时间复杂度 O(n)空间复杂度 O(1)
易错点
- 水量公式要减去当前柱高,结果小于 0 时按 0 算;先更新 leftMax 再算水量,避免把当前柱子当成边界。
- 移动指针前要比较 height[left] 和 height[right],只移动较矮的一侧;移动高的一侧会丢失尚未确定的边界。
- 空数组、单柱、完全平坦的数组都返回 0,循环和初始化要能处理。
逐步演示
参考代码
1function trap(height) {
2 let left = 0;
3 let right = height.length - 1;
4 let leftMax = 0;
5 let rightMax = 0;
6 let water = 0;
7
8 while (left < right) {
9 if (height[left] < height[right]) {
10 leftMax = Math.max(leftMax, height[left]);
11 water += leftMax - height[left];
12 left++;
13 } else {
14 rightMax = Math.max(rightMax, height[right]);
15 water += rightMax - height[right];
16 right--;
17 }
18 }
19
20 return water;
21}
效果图
当前场景
第 1 / 35 步