leetcode: Trapping Rain Water

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>,用来保存边界的位置。思路如下:

  1. 如果堆栈s2为空,把当前位置压入堆栈。
  2. 如果堆栈s2不为空:
    1. 如果栈顶所在位置的值大于当前位置的值,把当前位置压入堆栈。(A[i] < A[s2.top()])
    2. 如果前一条不满足,那么当前位置的值一定大于等于栈顶所在位置的值。(A[i] >= A[s2.top()])
      1. 如果堆栈s2不为空,并更新左边界位置为栈顶元素,如果左边界上的值大于当前位置的值,停止循环,不然弹出栈顶元素并继续比较。
      2. 将当前位置压入堆栈。
      3. 把当前元素所在位置压入堆栈。同时左边界和当前元素的位置正好构成一个容器区间,根据木板原理,容积由较小的值决定。如果s1不为空,栈顶元素可以和当前元素合并,弹出栈顶元素与当前区间合并,再继续循环检查栈顶元素,如果堆栈为空或者栈顶元素不能和当前区间合并,将当前元素压入堆栈。
  3. 遍历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 };
原文地址:https://www.cnblogs.com/panda_lin/p/trapping_rain_water.html