zoukankan      html  css  js  c++  java
  • LeetCode Trapping Rain Water

    class Solution {
    public:
        int trap(int A[], int n) {
            if (n < 1) return 0;
            vector<int> peaks;
            vector<int> peaks_tmp;
    
            int last_idx = 0;
    
            bool increasing = true;
            for (int i=1; i<n; i++) {
                if (A[i] < A[last_idx]) {
                    if (increasing) {
                        peaks.push_back(last_idx);
                    }
                    increasing = false;
                } else {
                    increasing = true;
                }
                last_idx = i;
            }
            if (increasing) peaks.push_back(n - 1);
    
            if (peaks.size() < 2) return 0;
            
            bool updated = true;
    
            while (updated) {
                updated = false;
                peaks_tmp.clear();
                peaks_tmp.push_back(peaks[0]);
                peaks_tmp.push_back(peaks[1]);
                for (int i=2; i<peaks.size(); i++) {
                    int tlen = peaks_tmp.size();
                    int ai = peaks_tmp[tlen - 2];
                    int bi = peaks_tmp[tlen - 1];
                    int ci = peaks[i];
    
                    if (A[ai] >= A[bi] && A[ci] >= A[bi]) {
                        peaks_tmp[tlen - 1] = ci;
                        updated = true;
                    } else {
                        peaks_tmp.push_back(ci);
                    }
                }
                swap(peaks, peaks_tmp);
            }
    
            int rain = 0;
    
            for (int i=1; i<peaks.size(); i++) {
                int left = peaks[i - 1];
                int right= peaks[i];
    
                int h = min(A[left], A[right]);
                int blocks = 0;
                for (int i=left + 1; i<right; i++) blocks += A[i] > h ? h : A[i];
                rain += h * (right - left - 1) - blocks;
            }
            return rain;
        }
    };

    先求出各个block的峰值,然后雨水肯定落在峰值block之间,对这些峰值block为界限的区间进行合并(对于序列A{4,1,3,1,5},第一个区间为A(0,2),第二个区间为A(2,4),由于A[4] > A[2] 且 A[0] > A[2]所以可以合并为区间A(0, 4)),直到不能继续合并,最终计算这些block区间所能积累的水量。

    再稍稍改进一下,合并过程在求峰值时同时进行,额外数组减少到一个

    class Solution {
    public:
            int trap(int A[], int n) {
            if (n < 1) return 0;
            vector<int> peaks;
    
            int last_idx = 0;
    
            bool increasing = true;
            for (int i=1; i<n; i++) {
                if (A[i] < A[last_idx]) {
                    if (increasing) {
                        peaks.push_back(last_idx);
                        compact(A, peaks);
                    }
                    increasing = false;
                } else {
                    increasing = true;
                }
                last_idx = i;
            }
            
            if (increasing) peaks.push_back(n - 1);
            compact(A, peaks);
            
            if (peaks.size() < 2) return 0;
    
            int rain = 0;
    
            for (int i=1; i<peaks.size(); i++) {
                int left = peaks[i - 1];
                int right= peaks[i];
    
                int h = min(A[left], A[right]);
                int blocks = 0;
                for (int i=left + 1; i<right; i++) blocks += A[i] > h ? h : A[i];
                rain += h * (right - left - 1) - blocks;
            }
            return rain;
        }
    
        void compact(int A[], vector<int> &peaks) {
            int len = peaks.size();
            if (len < 3) return;
            bool updated = true;
            while (updated && (len = peaks.size()) >= 3) {
                updated = false;
                int ai = peaks[len - 3];
                int bi = peaks[len - 2];
                int ci = peaks[len - 1];
                if (A[ai] >= A[bi] && A[ci] >= A[bi] ) {
                    peaks[len - 2] = ci;
                    peaks.pop_back();
                    updated = true;
                }
            }
        }
    };

    另外一种简洁方法参见:http://www.cnblogs.com/zhuli19901106/p/3542216.html,如下

    class Solution {
    public:
        int trap(int A[], int n) {
            if (n < 2) return 0;
            vector<int> lmax(n, 0);
            vector<int> rmax(n, 0);
            
            int m = A[n-1];
            for (int i=n-2; i >= 0; i--) {
                if (A[i] > m) m = A[i];
                rmax[i] = m;
            }
            
            m = A[0];
            for (int i=1; i<n; i++) {
                if (A[i] > m) m = A[i];
                lmax[i] = m;
            }
    
            int rain = 0;
            for (int i=0; i<n; i++) {
                int h = min(lmax[i], rmax[i]);
                int v = h - A[i];
                rain += v < 0 ? 0 : v;
                
            }
            return rain;
        }
    };

    第二轮:

    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!

    LH数组可以不用存储直接在最后一个循环过程中计算。

     1 class Solution {
     2 public:
     3     int trap(vector<int>& height) {
     4         int len = height.size();
     5         if (len == 0) {
     6             return 0;
     7         }
     8         vector<int> LH(len, 0);
     9         LH[0] = height[0];
    10         for (int i=1; i<len; i++) {
    11             LH[i] = max(LH[i-1], height[i]);
    12         }
    13         
    14         vector<int> RH(len, 0);
    15         RH[len-1] = height[len-1];
    16         for (int i=len-2; i>=0; i--) {
    17             RH[i] = max(RH[i+1], height[i]);
    18         }
    19         
    20         int water = 0;
    21         for (int i=0; i<len; i++) {
    22             int ah = min(LH[i], RH[i]);
    23             if (ah <= height[i]) {
    24                 continue;
    25             }
    26             water += ah - height[i];
    27         }
    28         return water;
    29     }
    30 };

     还有更高效的做法,真是智商碾压啊,短短几行,还不用额外空间,艹

    class Solution {
    public:
        int trap(vector<int>& height) {
            int len = height.size();
            int p = 0, q = len - 1;
            int maxh = 0;
            int sum = 0;
            while (p < q) {
                if (height[p] < height[q]) {
                    maxh = max(height[p], maxh);
                    sum += maxh - height[p];
                    p++;
                } else {
                    maxh = max(height[q], maxh);
                    sum += maxh - height[q];
                    q--;
                }
            }
            return sum;
        }
    };

     又从discuss中找到一种方法,似乎这种比较通用一些可以解决一些类似的问题:

    class Solution {
    public:
        int trap(vector<int>& height) {
            int len = height.size();
            stack<int> pos;
            int sum = 0;
            for (int i = 0; i < len; i++) {
                while (!pos.empty() && height[i] > height[pos.top()]) {
                    int base = height[pos.top()];
                    pos.pop();
                    if (!pos.empty()) {
                        int w = i - pos.top() - 1;
                        int h = min(height[i], height[pos.top()]) - base;
                        sum += w * h;
                    }
                }
                pos.push(i);
            }
            return sum;
        }
    };

    不过相比前一种使用了辅助空间。

  • 相关阅读:
    【数据库】事务,ACID,CAP和一致性
    线程,进程。多进程,多线程。并发,并行的区别
    mysql 集群 数据同步
    如何读取一个表的表类型,以及读取一个表中字段的类型.
    网络攻击技术开篇——SQL Injection
    MySQL数据库作发布系统的存储,一天五万条以上的增量,预计运维三年,怎么优化?
    程序员找工作那些事(一)幸存者偏差
    程序员
    preg_replace的一些细节
    HDU 1258 Sum It Up(dfs 巧妙去重)
  • 原文地址:https://www.cnblogs.com/lailailai/p/3856431.html
Copyright © 2011-2022 走看看