这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战
面试题 17.21. 直方图的水量
给定一个直方图(也称柱状图),假设有人从上面源源不断地倒水,最后直方图能存多少水量?直方图的宽度为 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
解题思路
维护一个单调递减的栈,当遍历到的元素大于栈中元素时,此时的栈顶元素就找到了它左边和右边第一个比它高的墙的高度了,就将栈中的两个元素和当前元素组成一个接雨水的区域。
做法:
- 若 height[i] <= 栈顶元素时,则当前的遍历的墙的高度入栈
- 若 height[i] > 栈顶元素时,则将当前栈顶元素出栈
top = stack.pop()
,并且 height[i] 为 height[top] 右边第一个比它高的墙,而新栈顶元素l=stack.peek()
为左边第一个比 height[top] 高的墙(找两个墙中较矮的墙),则可计算 height[top] 能存多少水Math.min(height[l],height[i])-height[top]
,再求雨水的宽度i-l-1
代码
class Solution {
public int trap(int[] height) {
Stack<Integer> stack=new Stack<>();
int n=height.length,res=0;
for(int i=0;i<n;i++)
{
while (!stack.isEmpty()&&height[i]>height[stack.peek()])
{
int top=stack.pop();
if(stack.isEmpty())
break;
int l=stack.peek();
int weight=i-l-1;
int h=Math.min(height[l],height[i])-height[top];
res+=h*weight;
}
stack.push(i);
}
return res;
}
}
时间复杂度:O(n),其中 n 是数组height 的长度。从 0 到 n−1 的每个下标最多只会入栈和出栈各一次。
空间复杂度:O(n),其中 n 是数组height 的长度。空间复杂度主要取决于栈空间,栈的大小不会超过 n。