携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情
接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
来源:力扣(LeetCode)链接:leetcode.cn/problems/tr…
分析
- 水存在于柱子之间,如果两个相邻柱子高度一个大一个小,那接水量是由小值来决定的,接水量=较小值。因此在针对数组时,面对某个下标i,需要向左、向右分别遍历,找到接水量,每个位置分别取最小值累积,即可得到总的接水量
优化
使用双指针优化
- 在向左、向右遍历算当前位置的接水量时,需要维护两个数组。但是最后相加的项是这两个数组中下标为i的最小值,所以只需要左右方向的最大值和双指针LR,可以有效降低空间复杂度,且数组只遍历一遍。
- LR的移动,更新leftMax和rightMax,当左边小于右边,那左边接到的雨水是算到总接水量的,所以左指针移动,右指针移动逻辑类似。
代码
/**
* @param {number[]} height
* @return {number}
*/
var trap = function(height) {
let ans = 0
let left = 0
const len = height.length
let right = len -1
let leftMax = 0
let rightMax = 0
while(left<right) {
leftMax = Math.max(leftMax, height[left])
rightMax = Math.max(rightMax, height[right])
if(leftMax < rightMax) {
ans += leftMax - height[left]
left ++
} else {
ans+= rightMax - height[right]
right --
}
}
return ans
};
另一种分析
- 把y轴当做基准轴,记录x下标,根据heght[x]和当前最大的值坐标对应的位置,坐标相减乘高度差也可得到接水量
- 因为涉及到最大值的坐标,每次都能直接获取到最大值,可以维护一个单调栈,栈顶元素即最大值
/**
* @param {number[]} height
* @return {number}
*/
var trap = function(height) {
let stack = []
let ans = 0
const len = height.length
for(let i=0;i<len;i++) {
while(stack.length && height[i] > height[stack[stack.length -1]]) {
const top = stack.pop()
if(!stack.length) {
break
}
const left = stack[stack.length -1]
const curWidth = i-left-1
const curHeight = Math.min(height[left], height[i]) - height[top]
ans += curWidth * curHeight
}
stack.push(i)
}
return ans
};
总结
- 做这道题的时候,关于接雨水的量,想到了短板原理,所有板子变得一样一样高才能盛更多的谁,加强自己薄弱的地方,可以变得更强
- 今天又是有收获的一天