http://oj.leetcode.com/problems/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. For example, Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6. The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
思路:
暴力方法肯定是能解决问题的,但是复杂度只能呵呵了。园子里转过一条新闻“面试题分析:我的Twitter技术面试失败了”,里面T社面试就是这题。我不能保证这个解法效率最优,但是复杂度可以通过OJ。基本原理就是找到其中一个个小的容器区间。需要两个堆栈和一个合并区间函数配合。第一个堆栈s1的类型为stack<pair<int, int> >,用来保存容器区间;第二个堆栈s2的类型为stack<int>,用来保存边界的位置。思路如下:
- 如果堆栈s2为空,把当前位置压入堆栈。
- 如果堆栈s2不为空:
- 如果栈顶所在位置的值大于当前位置的值,把当前位置压入堆栈。(A[i] < A[s2.top()])
- 如果前一条不满足,那么当前位置的值一定大于等于栈顶所在位置的值。(A[i] >= A[s2.top()])
- 如果堆栈s2不为空,并更新左边界位置为栈顶元素,如果左边界上的值大于当前位置的值,停止循环,不然弹出栈顶元素并继续比较。
- 将当前位置压入堆栈。
- 把当前元素所在位置压入堆栈。同时左边界和当前元素的位置正好构成一个容器区间,根据木板原理,容积由较小的值决定。如果s1不为空,栈顶元素可以和当前元素合并,弹出栈顶元素与当前区间合并,再继续循环检查栈顶元素,如果堆栈为空或者栈顶元素不能和当前区间合并,将当前元素压入堆栈。
- 遍历s1并计算容积。
1 class Solution { 2 public: 3 bool isInRange(pair<int, int> &left, pair<int, int> &right) { 4 return (left.first >= right.first) && (left.second <= right.second); 5 } 6 7 int getVolume(int A[], pair<int, int> range) { 8 int left = range.first, right = range.second; 9 int volume = min(A[left], A[right]) * (right - left - 1); 10 11 for (int i = left + 1; i < right; ++i) { 12 volume -= A[i]; 13 } 14 15 return volume; 16 } 17 18 int trap(int A[], int n) { 19 stack<pair<int, int> > ranges; 20 stack<int> bars; 21 22 for (int i = 0; i < n; ++i) { 23 if (bars.empty()) { 24 bars.push(i); 25 } 26 else { 27 if (A[i] < A[bars.top()]) { 28 bars.push(i); 29 } 30 else { 31 int left; 32 pair<int, int> range; 33 34 while (!bars.empty()) { 35 left = bars.top(); 36 if (A[left] > A[i]) { 37 break; 38 } 39 40 bars.pop(); 41 } 42 43 bars.push(i); 44 range.first = left; 45 range.second = i; 46 47 while (!ranges.empty()) { 48 if (isInRange(ranges.top(), range)) { 49 ranges.pop(); 50 } 51 else { 52 break; 53 } 54 } 55 56 ranges.push(range); 57 } 58 } 59 } 60 61 int volume = 0; 62 63 while (!ranges.empty()) { 64 volume += getVolume(A, ranges.top()); 65 ranges.pop(); 66 } 67 68 return volume; 69 } 70 };