LeetCode 42. Trapping Rain Water

1. 题目描述

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!

2. 解题思路

我们的基本思路呢, 就是找到这个数组从左向右递增的的位置, 同时找到从右向左的递增位置, 然后根据这些递增位置之间所形成的区间, 计算存储的水的量的多少。

3. code

class Solution {
public:
    int trap(vector<int>& height) {
        if (height.size() <= 1)
            return 0;

        // 找到递增 与 递减的关键节点
        vector<int> incr_pos_l, incr_pos_r;
        int mymax = 0;
        for (int i = 0; i != height.size(); i++){
            if (height[i] > mymax){
                incr_pos_l.push_back(i);
                mymax = height[i];
            }
        }

        mymax = 0;
        for (int i = height.size() - 1; i >= 0; i--){
            if (height[i] > mymax){
                incr_pos_r.push_back(i);
                mymax = height[i];
            }
        }

        // 计算水容量
        int voll = computeVal(incr_pos_l, height, true);
        int volr = computeVal(incr_pos_r, height, false);

        int val = 0;
        for (int j = incr_pos_l.back(); j != incr_pos_r.back(); j++){
            val += height[incr_pos_l.back()] - height[j];
        }

        return voll + volr + val;
    }

private:
    void myincr(int & i, bool isLeft){
        isLeft ? i++ : i--;
    }

    int computeVal(vector<int> incr_pos, vector<int>& height, bool isLeft){
        int sum = 0;
        for (int i = 0; i < incr_pos.size() - 1; i++){
            int val = 0;
            for (int j = incr_pos[i]; j != incr_pos[i + 1]; myincr(j, isLeft)){
                val += height[incr_pos[i]] - height[j];
            }
            sum += val;
        }

        return sum;
    }
};

4. 大神解法

4.1 demo1 两端逼近

两端逼近, 找到他们两端的所记录到的最大值, 并计算存储的水量

Keep track of the maximum height from both forward directions backward directions, call them leftmax and rightmax.

public int trap(int[] A){
    int a=0;
    int b=A.length-1;
    int max=0;
    int leftmax=0;
    int rightmax=0;
    while(a<=b){
        leftmax=Math.max(leftmax,A[a]);
        rightmax=Math.max(rightmax,A[b]);
        if(leftmax<rightmax){
            max+=(leftmax-A[a]);       // leftmax is smaller than rightmax, so the (leftmax-A[a]) water can be stored
            a++;
        }
        else{
            max+=(rightmax-A[b]);
            b--;
        }
    }
    return max;
}

4.2 demo2

Keep track of the already safe level and the total water so far. In each step, process and discard the lower one of the leftmost or rightmost elevation.

C

Changing the given parameters to discard the lower border. I'm quite fond of this one.

int trap(int* height, int n) {
    int level = 0, water = 0;
    while (n--) {
        int lower = *height < height[n] ? *height++ : height[n];
        if (lower > level) level = lower;
        water += level - lower;
    }
    return water;
}
Slight variation with two pointers (left and right).

int trap(int* height, int n) {
    int *L = height, *R = L+n-1, level = 0, water = 0;
    while (L < R) {
        int lower = *L < *R ? *L++ : *R--;
        if (lower > level) level = lower;
        water += level - lower;
    }
    return water;
}
C++

With left and right index.

int trap(vector<int>& height) {
    int l = 0, r = height.size()-1, level = 0, water = 0;
    while (l < r) {
        int lower = height[height[l] < height[r] ? l++ : r--];
        level = max(level, lower);
        water += level - lower;
    }
    return water;
}
With left and right iterator.

int trap(vector<int>& height) {
    auto l = height.begin(), r = height.end() - 1;
    int level = 0, water = 0;
    while (l != r + 1) {
        int lower = *l < *r ? *l++ : *r--;
        level = max(level, lower);
        water += level - lower;
    }
    return water;
}

你可能感兴趣的:(LeetCode)