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;

    }

};

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

你可能感兴趣的:(LeetCode)