题目
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
思路
双指针夹逼
- 首先,找到能存水的左边界索引left和右边界索引right。
对于左边界索引left是从数组头到数组尾方向看,第一次出现下降趋势的那个索引的位置。
对于右边界索引right是从数组尾到数组头方向看,第一次出现下降趋势的那个索引的位置。 - 记录左边界和右边界的高度,分别记作leftHeight和rightHeight。显然,雨水数是由较低的边界所决定的。
a.如果leftHeight小于等于rightHeight。
如果此时满足left < right,说明左右边界还没有重合,尝试着令left加1。如果left位置能够存储雨水,则更新结果的值。如果left位置不能存储雨水,说明left位置的高度大于等于leftHeight,这时我们应该进入下一轮循环,更新leftHeight的值。
b.如果leftHeight大于rightHeight
如果此时满足left < right,说明左右边界还没有重合,尝试着令right减1。如果right位置能够存储雨水,则更新结果的值。如果right位置不能存储雨水,说明right位置的高度大于等于rightHeight,这时我们应该进入下一轮循环,更新rightHeight的值。
该思路的时间复杂度是O(n)级别的,空间复杂度是O(1)级别的。
int getHe(vector<int> a)
{
int result = 0;
int len = a.size()-1;
if (len<=1)
return result;
int left = 0,right = len-1;
while (left<len-1&&a[left+1]<a[left])
{
left++;
}
while (right>0&&a[right-1]<a[right])
{
right++;
}
while (left<right)
{
int lHigest = a[left];
int rHigest = a[right];
if (a[left]<=a[right])
{
while (left<right)
{
left++;
if (a[left]<lHigest)
result+=(lHigest-a[left]);
else
break;
}
} else
{
while (left<right)
{
right--;
if (a[right]<rHigest)
result+=(rHigest-a[right]);
else
break;
}
}
}
return result;
}