双指针
在暴力解法的核心主要是查找出左右两边的最大值,但是我们仔细分析会发现,只要 right_max[i] > left_max[i],柱子i位置的最大存水量就由left_max决定;反之如果 left_max[i] > right_max[i],则由right_max决定。
根据这个思路,我们还是先从左往右扫描数组,我们可以认为如果一侧有更高的柱子(例如右侧),积水的高度依赖于当前方向的高度(从左到右)。当我们发现另一侧(右侧)的条形块高度不是最高的,我们则开始从相反的方向遍历(从右到左)。
此时我们维护左右两个指针,通过两个指针交替进行遍历,实现一次遍历完成。
对于位置left而言,它左边的最大值一定是left_max,右边的最大值大于等于right_max。如果此时left_max < right_max,那么它就能计算出它的位置能存多少水,无论右边将来会不会出现更大的值,都不影响计算出的结果,所以当height[left] < height[right] 时,我们去处理left指针。反之,我们去处理right指针。
var trap = function(height) {let sum = 0;let left_max = 0;let right_max = 0;let left = 0;let right = height.length - 1;while(left < right) {if (height[left] < height[right]) {left_max = Math.max(left_max, height[left]);sum += left_max - height[left];left++;} else {right_max = Math.max(right_max, height[right]);sum += right_max - height[right];right--;}}return sum;};
// 单调栈var trap = function(height) {let ans = 0;let left = 0, right = height.length - 1;let leftMax = 0, rightMax = 0;while (left < right) {leftMax = Math.max(leftMax, height[left]);rightMax = Math.max(rightMax, height[right]);if (height[left] < height[right]) {ans += leftMax - height[left];++left;} else {ans += rightMax - height[right];--right;}}return ans;};
var trap = function(height) {let ans = 0;const stack = [];const n = height.length;for (let i = 0; i < n; ++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 currWidth = i - left - 1;const currHeight = Math.min(height[left], height[i]) - height[top];ans += currWidth * currHeight;}stack.push(i);}return ans;};作者:LeetCode-Solution链接:https://leetcode-cn.com/problems/trapping-rain-water/solution/jie-yu-shui-by-leetcode-solution-tuvc/来源:力扣(LeetCode)著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
