Trapping Rain Water
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.
分析:这道题还是有难度的。首先要明确如何计算trapped water,如果一个小矩形块上可以trap water,那么它的左侧和右侧必须有比它高的矩形块,而一个矩形块trap water的多少则由左侧最高及右侧最高的矩形块中较矮的那个决定。由上面的分析,我们就可以先算出每个矩形块左侧最大值和右侧最大值,然后计算trap water的量,一个实现代码如下,时间复杂度为O(n),但需要3个pass,空间复杂度为O(n)。
1 class Solution { 2 public: 3 int trap(int A[], int n) { 4 vector<int> max_left(n,0); 5 vector<int> max_right(n,0); 6 int sum = 0; 7 for(int i = 1; i < n; i++){ 8 max_left[i] = max(max_left[i-1], A[i-1]); 9 max_right[n-1-i] = max(max_right[n-i],A[n-i]); 10 } 11 for(int i = 1; i < n-1; i++){ 12 int height = min(max_left[i],max_right[i]); 13 if(height > A[i]) 14 sum += height - A[i]; 15 } 16 return sum; 17 } 18 };
我们还可以在上面的基础上做优化,我们的确需要每个矩形块左侧的最大值和右侧的最大值,但事先计算并保存是不必要的。一个巧妙的解决办法是先找到所有矩形块的最大值,然后以该最大值为分界分成两部分,这个最大矩形块是左侧子数组的右侧最大值,是右侧子数组的左侧最大值。然后对于左侧子数组,我们只要从左到右扫描找到左侧最大值即可;对于右侧子数组,从右到左扫描找到右侧最大值。时间复杂度为O(n),但只有两个pass,空间复杂度为O(1)。代码如下:
class Solution { public: int trap(int A[], int n) { int result = 0; int maxBar = 0; for(int i = 1; i < n; i++) if(A[i] > A[maxBar]) maxBar = i; //from left to right for(int i = 0, peak = 0; i < maxBar; i++){ if(A[i] < peak) result += peak - A[i]; else peak = A[i]; } //from right to left for(int i = n-1, peak = 0; i > maxBar; i--){ if(A[i] < peak) result += peak - A[i]; else peak = A[i]; } return result; } };
除上面的解法外,我们还可以采用与Largest Rectangle in Histogram中用栈保存数据的方法。在Largest Rectangle in Histogram中,栈保存的是某元素左侧的较小值,所以如果当前元素大于栈顶元素,就把当前元素压栈,否则将栈顶元素出栈直到栈顶元素小于当前元素为止。这道题中恰好与Largest Rectangle in Histogram相反,栈保存的是某元素左侧的较大值,如果当前元素小于栈顶元素,就把当前元素压栈,否则将栈顶元素出栈直到栈顶元素大于当前元素为止。当然我们要清楚,这种方法的trapped water是按横着的长条来算的,不同于第一二中方法按竖着的长条来算。代码如下:
class Solution { public: int trap(int A[], int n) { int result = 0; stack<int> Q;//stores element index for(int i = 0; i < n;){ if(Q.empty() || A[Q.top()] > A[i]){ Q.push(i); i++; } else{ int index = Q.top(); Q.pop(); if(!Q.empty()) result += (min(A[i], A[Q.top()]) - A[index]) * (i - Q.top() -1); } } return result; } };