方法一
从左向右遍历,一般的,对第i个柱子,向右找j柱,使得以i柱为左边界,以j柱为右边界形成“凹水槽”。分两种情况
-
j柱是第一个大于或等于i柱的柱子,这时顺便计算“凹水槽”盛水量, i = j
-
找不到大于或等于i柱的柱子,这时的j柱为i柱右边最大的柱子,也可以顺便计算“凹水槽”盛水量(至于怎么计算,请读者自己琢磨),i = j
算法缺点:对于第2种情况,要高效的处理是比较困难的,方法可能还是存在的,但是空间代价一定不小。
方法二
对方法一改进,从两边遍历。从左向右遍历时如果遇到第二种情况,就后停下来。从右向左遍历与从左向右遍历对称。
这种算法克服了第一种情况的困难或性能差。
程序按第方法二实现。
class Solution {
public:
int searchBiggerFromLeft(const vector<int>& arr, int beg, int end, long long &water)
{
int base = arr[beg];
int j;
for (j = beg + 1; j <= end; j++)
{
if (arr[j] != base)
{
break;
}
}
beg = j - 1;
base = arr[beg];
int i;
for (i = beg + 1; i <= end; i++)
{
if (arr[i] < base)
{
water += base - arr[i];
}
else
{
break;
}
}
if (i <= end)
{
return i;
}
water = 0;
return beg;
}
int searchBiggerFromRight(const vector<int>& arr, int beg, int end, long long &water)
{
int base = arr[end];
int j;
for (j = end - 1; j >= beg; j--)
{
if (arr[j] != base)
{
break;
}
}
end = j + 1;
base = arr[end];
int i;
for (i = end - 1; i >= beg; i--)
{
if (arr[i] < arr[end])
{
water += arr[end] - arr[i];
}
else
{
break;
}
}
if (i >= beg)
{
return i;
}
water = 0;
return end;
}
long long maxWater(vector<int>& arr) {
// write code here
long long sum = 0;
int i = 0;
int j = arr.size() - 1;
while (i < j)
{
long long water = 0;
int biggerIndex = searchBiggerFromLeft(arr, i, j, water); //找不到时返回输入的i,water为0
i = biggerIndex;
sum += water;
water = 0;
biggerIndex = searchBiggerFromRight(arr, i, j, water); //找不到时返回输入的j,water为0
sum += water;
j = biggerIndex;
}
return sum;
}
};