来了来了,今天来分享一个力扣上评价困难的题目------接雨水(Leetcode 42题)。当时在写成最多水的容器这道题目的时候,就听说还有道接雨水的题目。今天终于让我见到真实面貌了。话不多说,直接开始正题吧!这道题目的主要的算法思想还是双指针哦!因为我现在专门学习做双指针。
# 手刃算法第八式:接雨水
给定
n
个非负整数表示每个宽度为1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
题目分析
刚拿到这道题目的时候我就感觉有点摸不到头脑。从示例上可以知道题目的意思,就是看这些坑里面能积多少水。首先我的想法就是,设置一个起始点,然后找到其左边最高的,再找到其右边最高的,然后根据木桶效应,取最短的那边就可以减去它本身的高度就可以得到起始点最多能接多少雨水,然后继续得到下一个起始点能接的雨水量。
emmmm,听着就好麻烦。
看这个图是不是就直观一点了。应该是直观了一点。
这时候就要写代码实现了!
代码实现
通过刚才的算法分析,编写如下的代码:
ini
var trap = function(height) {
let sum = 0;
let len = height.length - 1;
for (let i = 1; i < len; i++) {
let right = i + 1;
let left = i - 1;
let maxLeft = height[i];
let maxRight = height[i];
while (left >= 0) {
maxLeft = Math.max(maxLeft, height[left]);
left--;
}
while (right <= len) {
maxRight = Math.max(maxRight, height[right]);
right++;
}
let waterLevel = Math.min(maxLeft, maxRight);
sum += Math.max(0, waterLevel - height[i]);
}
return sum;
}
通过这个来运行的话还是能运行出来的。
但是!!!服了,提交的时候给我来个这个!
我只能说,6啊!还是我的代码不够完美。哎,可是这已经是我能写的出来的了。
没办法只能去寻求帮助了。
别人家的想法
直接设置左右两个指针,一个指针指向数组头部,一个指针指向数组尾部,然后 设置两个变量分别记录左右两边的最大高度。如果左边的高度小于右边的高度,则用左边的最大高度减去左边当前的高度就是此时这个格子能接到的雨水量。相反就用右边最大高度减去右边当前的高度。语言表达能力有限,感觉讲清楚了,有感觉没有说清楚。 还是看图说话吧!!!
他这个想法和我的是差不多的,但是还是挺猛的!这样就不需要用两个循环了,一个循环就搞定了。
具体代码实现
ini
var trap = function(height) {
if (height.length === 0) return 0;
let left = 0, right = height.length - 1;
let maxLeft = 0, maxRight = 0;
let sum = 0; // 初始化积水总量
while (left < right) {
if (height[left] <= height[right]) {
maxLeft = Math.max(maxLeft, height[left]);
sum += maxLeft - height[left];
left++;
} else {
maxRight = Math.max(maxRight, height[right]);
sum += maxRight - height[right];
right--;
}
}
return sum;
}
在回过头来看我写的代码,就跟现在看小学生的作文一样。我咋就想不到呢,同样都是双指针,咋差距这么大。难受了~
学到了学到了!以后再碰到要学会这样!
结语
这道题目说实话对我来说还是有难度的,不过当理清楚了还是可以拿下的。虽然我的代码比较low,但是最起码写出来了,也算是个进步吧!在b站上学习这个,好像说还有一种单调栈的方法,emmm,单调栈是啥,有没有大佬可以给解答一下的。今晚就到这里,晚安啦,明天也要努力哦!