运行结果
执行结果:通过
执行用时 :2 ms, 在所有 Java 提交中击败了50.62%的用户
内存消耗 :37.5 MB, 在所有 Java 提交中击败了83.13%的用户
代码与注释
class Solution {
public int trap(int[] height) {
int left = 1; // 左指针
int right = height.length-2; // 右指针
int left_max = 0; // 记录左最高
int rigth_max = 0; // 记录右最高
int sum = 0;
while (left <= right)
{
// 如果考察的列的左边列比右边的列小
if (height[left-1] < height[right+1])
{
left_max = Math.max(left_max, height[left-1]);
if (left_max > height[left]) sum += left_max - height[left];
left++;
}
// 如果考察的列左边的列大于等于右边的列
else
{
rigth_max = Math.max(rigth_max, height[right+1]);
if (rigth_max > height[right]) sum += rigth_max - height[right];
right--;
}
}
return sum;
}
}
做题体会
- 用双指针法,较矮的向较高的移动,只遍历一次,将代码的复杂度降低到O(n),n为数组长度。
- 主要思想是考察每一列能盛多少雨水,总的雨水数是每列雨水的总和。
- 每列能盛多少雨水的关键在于,当前列的高度是否比左右最高列的矮的那个还要矮,如果是的话,那么盛的雨水就等于左右最高列的矮的那个减去当前列的高度,否则当前列不能盛雨水。
- 如何知道左右最高的列中矮的那一个呢?传统思路是直接比较两个列的高度,这里的思路比较巧妙,通过判断height[left-1] < height[right+1]来间接的得到,left_max一定是小于right_max的,因为left_max取自height[left-1],而right_max取自height[right+1]。
- 不关心左右最高的具体位置,只关心其具体高度,左右最高在遍历过程中不断被更新,从左往右遍历,关心历史左最高,因为历史左最高,一定小于历史右最高。从右往左遍历,关心历史右最高,因为历史右最高一定小于历史左最高,通过比较条件,把当前列需要跟两个最高比较的情况,简化成了跟两者中最矮的比较。
- 当前列的上一个历史状态,谁矮就在谁的方向上推进,考察谁。