面试题 17.21. 直方图的水量

528 阅读1分钟

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

面试题 17.21. 直方图的水量

给定一个直方图(也称柱状图),假设有人从上面源源不断地倒水,最后直方图能存多少水量?直方图的宽度为 1。

image.png

上面是由数组 [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

解题思路

维护一个单调递减的栈,当遍历到的元素大于栈中元素时,此时的栈顶元素就找到了它左边和右边第一个比它高的墙的高度了,就将栈中的两个元素和当前元素组成一个接雨水的区域。

image.png

做法:

  1. 若 height[i] <= 栈顶元素时,则当前的遍历的墙的高度入栈
  2. 若 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。