Trapping Rain Water
Two Pointers
, Stack
, Dynamic Programming
Hard
Question
Given n
non-negative integers representing an elevation map where the width of each bar is 1
, compute how much water it is able to trap after raining.
Trapping Rain Water
Example
Given [0,1,0,2,1,0,1,3,2,1,2,1]
, return 6
.
Challenge
O(n) time and O(1) memory
O(n) time and O(n) memory is also acceptable.
Tags
Two Pointers Forward-Backward Traversal Array
Related Problems
Medium Container With Most Water
Hard Trapping Rain Water II
Candy
Analysis
Reference: https://leetcode.com/articles/trapping-rain-water/
Brute Force
最直觉的想法就是对于每个bar,找到其左边和右边最大的bar height: leftMax, rightMax,再减去bar本身的高度heights[i],就得到该处能存水的量。嵌套两重循环,每次只储存某个bar的左右最大height,因此
Time Complexity O(n^2), Space Complexity O(1)
Dynamic Programming
对于每一个bar来说,能装水的容量取决于左右两侧bar的最大值。扫描两次,一次从左向右,记录对于每一个bar来说其左侧的bar的最大高度left[i],一次从右向左,记录每一个bar右侧bar的最大高度right[i]。第三次扫描,则对于每一个bar,计算
(1)左侧最大height和当前bar的height的差值(left[i] - heights[i])
(2)右侧最大height和当前bar的height的差值(right[i] - heights[i]),
取(1),(2)中结果小的那个作为当前bar的蓄水量。最终求和得到总蓄水量。或者直接找到bari
两侧最大height中最小的那个,再找与heights[i]的大于零的差值即可。
The water each bar can trap depends on the maximum height on its left and right. Thus scan twice - from left to right, and right to left and record the max height in each direction. The third time calculate the min difference between left/right height and current bar height. Sum the trapped water to get the final result.
简而言之:找左边最大和右边最大可以通过两个dp数组来存起来.
dpLeft[i] = Math.max(dpLeft[i - 1], height[i]); dpRight[i] = Math.max(dpRight[i + 1], height[i]);
Time: O(N), Space: O(2*N)
Two Pointers
@Grandyang: 我们来看一种只需要遍历一次即可的解法,这个算法需要left和right两个指针分别指向数组的首尾位置,从两边向中间扫描,在当前两指针确定的范围内,先比较两头找出较小值,如果较小值是left指向的值,则从左向右扫描,如果较小值是right指向的值,则从右向左扫描,若遇到的值比当较小值小,则将差值存入结果,如遇到的值大,则重新确定新的窗口范围,以此类推直至left和right指针重合。
Time: O(N), Space: O(1)
Monotonic Stack
@reeestart: 和largest rectangle in histogram一样的思路. 只不过histogram是用递增栈, 这道题是使用递减栈. stack里存的也是index.
每次出栈的时候是处理出栈的栈顶元素而非当前元素. 因为每次需要出栈的时候我们可以确定:
height[stk.peek()] < height[stk.peek().peek()], stk.peek().peek() 就是栈顶第二大的元素.
height[stk.peek()] < height[i]
Solution
Brute Force
Dynamic Programming
Two Pointers
Monotonic Stack
Reference
Last updated