在二维的平面上,有许多堵高低不同的墙,这些墙有一个神奇的性质,那就是装水,如果有三堵墙,从左到右排列,高度分别为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))
这个复杂度是我瞎猜的,因为我觉得这玩意和快排差不多
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
};