之前解决方法
题目:接雨水
给定 n 个非负整数表示每个宽度为 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 个单位的雨水(蓝色部分表示雨水)。
思路分析
经过前两次的题解,发现总是总是会遍历多次,就像有没有方法可以一次遍历解决。很明显双指针就可以对其优化。
前一次使用动态规划的思路是从左至右缓存下每个位置之前的最高的柱子,以及从右到左每个位置之后的最高的柱子。现在使用双指针之后就可以边运行边计算两值,以达到一次遍历便可计算出结果。
首先定义两个变量左侧当前柱子之前的最大值 leftMax
右侧当前位置之后的最高柱子的高度 rightMax
,而初始值也为对应的 0 和 数组的最后一个位置的值。还需要两个指针用来表示当前左右两侧指针所在位置 left
和 right
,left
和right
的索引也默认从 1 和而这个循环的边界就是 左指针小于右指针的索引。
如果左指针值小于右指针值,然后与当前位置之前的最高柱子的高度(leftMax
)进行比较,若大于leftMax
则将当前位置柱子的高度赋值给 leftMax
,若小于等于leftMax
,则表示可以储水,那么就可以计算储水量了,公式和之前的一样 res = min(leftMax, rightMax) - height[i]
,计算完之后,左指针右移。
如果左指针大于等于右指针,操作与以上也类似。
只进行了一次循环,也没有使用到多余的变量,所以: 时间复杂度:O(n) 空间复杂度:O(1)
AC 代码
// 双指针
function trap(height = []) {
let len = height.length
let leftMax = 0
let rightMax = 0
let left = 0
let right = len - 1
let res = 0
while (left < right) {
if (height[left] < height[right]) {
if (leftMax < height[left]) {
leftMax = height[left]
} else {
res += leftMax - height[left]
}
left++
} else {
if (rightMax < height[right]) {
rightMax = height[right]
} else {
res += rightMax - height[right]
}
right--
}
}
return res
}
// 测试
console.log(trap([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]))
总结
在之前动态规划之上再次进行了优化,这次代码相对来说已经很好了,时间和空间,都应该符合要求了。双指针之前就有了解,但一下遇到相关题型,还是不能立马想到,还是得多刷题。(一个题水了三篇文章,知足了。)