[置顶] Trapping Rain Water

题目大意

在二维的平面上,有许多堵高低不同的墙,这些墙有一个神奇的性质,那就是装水,如果有三堵墙,从左到右排列,高度分别为2、 1、 2,那么,这三堵墙就可以装下1个单位的水,现在给你每堵墙的高度,请求出最多能装多少水。

思路

最开始的想法是暴力找第二高的墙,然后把每堵墙和它做差就可以找了,但是这样是不对的。
后来想把不断找第二、三、四……高的墙然后做差,主要思路是找到两个不能储水的墙,这两堵墙中间的格子是可以储水的,但是1、 2、 3、 4、 5这样的又会出事。
于是正确的做法是先找到最高的墙,然后往两边搜索次高的墙,这样可以得到最高墙与左次高墙之间的储水量L和最高墙与右次高墙之间的储水量R。
然后把左次高墙更新为左最高墙。此时左最高墙右边的储水量是已经求出来的,所以只要求左最高墙左边的储水量,方法同上,找到左最高墙左边(不含)的最高墙。
右边同理可知。

复杂度分析

求出储水量是循环n次,每次找最大值需要遍历整个待计算区间。然后二分的成本是log(n)。更新最大值这个操作最坏情况是n*n的。
比如说1、 2、 3 … n、 n-1、 n-2、 … 3、 2、 1这种情况
最开始是循环了2n - 1次,然后找左边需要循环n - 1次、n - 2次 …… 所以最坏情况下,这里需要消耗掉 n * n 级别的时间。
最好的情况是头尾就是次高值,这样一次性就能过。只需要 n 级别的时间。
所以平均一下,复杂度应该是O(n*log(n))
这个复杂度是我瞎猜的,因为我觉得这玩意和快排差不多

CODE

class Solution {
public:
    #define INF 2147483647
    #define MAXN 255
    #define NUL 0
    int trap(vector<int>& height) 
    {
        if (NUL == height.size()) return 0;
        int i;
        int n = height.size();
        int A[height.size()];
        for (i = 0; i < n; i++)
        {
            A[i] = height[i];
        }
        int big = find_big(0, n, A);
        int ans = get_water_left(0, big, A);
        ans += get_water_right(big, n, A);
        return ans;
    }//trap

    int find_big(int a, int b, int A[])
    {
        int i, ans = -INF, num;
        for (i = a; i < b; i++) 
        {
            if (ans < A[i]) 
            {
                ans = A[i];
                num = i;
            }
        }
    return num;
    }//find_big

    int get_water_left(int a, int b, int A[])
    {
        int i, ans = 0;
        if (b-a <= 1) return 0;
        int l = find_big(a, b, A);
        for (i = l + 1; i < b; i++) ans += A[l]-A[i];
        return ans + get_water_left(a, l, A);
    }//get_water_left

    int get_water_right(int a, int b, int A[])
    {
        int i, ans=0;
        if (b - a <= 1) return 0;
        int r = find_big(a + 1, b, A);
        for (i = a+1; i < r; i++) ans += A[r] - A[i];
        return ans + get_water_right(r, b, A);
    }//get_water_right
};

你可能感兴趣的:(LeetCode,分治算法)