这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战
这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。
148. 接雨水 (trapping-rain-water)
标签
- 双指针
- 困难
题目
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,
在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2
输入:height = [4,2,0,3,2,5]
输出:9
基本思路
我们拿到一个问题,如果一时想不到其他好方法,不要愣着,能解出问题,低效的代码也行,先解出来!任何题目大多又有暴力方式,思考简单,但效率不高。
我们先看穷举法,简单来说就是遍历每个位置能放下的水有多少,如图
i
,的位置能放下的水是,左边最高墙 l_maxH = 3
,右边最高 r_maxH = 4
,木桶原理取小的那个,再减去当前 i
柱子的高度就得到盛水的体积了,就是 3 - 1 = 2
代码也非常暴力
var trap = function(height) {
let res = 0, len = height.length
if (len === 0) return 0
// 其实就是遍历寻找每个位置上左右最高的位置
for (let i = 1; i < len-1; i++) {
let l_maxH = 0
let r_maxH = 0
// 找右边最高的柱子
for (let j = i; j < len; j++) {
// 每轮比较更新最大值, 最后就是该位置上右边最高柱子
r_maxH = Math.max(r_maxH, height[j])
}
// 同样的,找左边最高的柱子
for (let k = i; k >= 0; k--) {
// 每轮比较更新最大值, 最后就是该位置上右边最高柱子
l_maxH = Math.max(l_maxH, height[k])
}
// 对比两边柱子的最小值,木桶原理,取小的那个,
// 然后减去当前高度就是该位置上能存的水量
res += Math.min(l_maxH, r_maxH) - height[i]
}
return res
}
let height = [0,1,0,2,1,0,1,3,2,1,2,1]
console.log(trap(height))
复杂度 O(n^2) 那么有什么方法去优化呢
双指针
其实整体思路大致相似,有两个指针从两头向中间逼近,如图,left 指针坐标位置能承载的水量,其实只跟 l_maxH
有关,跟 r_maxH
是无关的。所以只要动态更新左右最高墙还是取木桶短板做墙,算出每个位置的盛水量即可。
双指针
var trap = function(height) {
let len = height.length, res = 0
if (len === 0) return 0
// 双指针一左一右放边界坐标上, left -> 从左往右,right 反之
let left = 0
let right = len - 1
// 左边的最大值,从左往右遍历获得
let l_max = height[0]
// 右边的最大值,从右往左遍历获得
let r_max = height[len-1]
while (left <= right) {
l_max = Math.max(l_max, height[left])
r_max = Math.max(r_max, height[right])
// 取短的墙
if (l_max <= r_max) {
res += l_max - height[left]
left++
} else {
res += r_max - height[right]
right--
}
}
return res
};
另外向大家着重推荐下这个系列的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列
今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 点击此处交个朋友
Or 搜索我的微信号infinity_9368
,可以聊天说地
加我暗号 "天王盖地虎" 下一句的英文
,验证消息请发给我
presious tower shock the rever monster
,我看到就通过,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧