• 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 };
  • 相关阅读:
    操作系统
    redis
    数据库原理与mysql
    计算机网络
    重写、重载、隐藏以及多态分析
    c++复习重点
    重装系统记录
    正则表达式匹配ip地址
    信号量和互斥锁的区别 互斥量与临界区的区别
    为Markdown文件生成目录
  • 原文地址:https://www.cnblogs.com/panda_lin/p/trapping_rain_water.html
Copyright © 2020-2023  润新知