42. 接雨水

92 阅读2分钟

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

42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

在这里插入图片描述

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 示例 2:

输入:height = [4,2,0,3,2,5] 输出:9

解题思路

  • 维护一个单调栈,单调栈内的元素是递减的,当前遍历的元素如果大于栈顶的元素,有因为栈是单调递减的,所以栈顶元素的前面存在更大的元素,因此就可以形成一个接雨水的区域了。

  • 接雨水的宽度由左右两个元素的下标差决定,而高度由左右两边较小的那个元素和栈顶元素决定

遍历所有高度:

  1. 当前高度小于等于栈顶高度,入栈,指针后移。

  2. 当前高度大于栈顶高度,出栈,计算出当前墙和栈顶的墙之间水的多少,然后计算当前的高度和新栈的高度的关系,重复第 2 步。直到当前墙的高度不大于栈顶高度或者栈空,然后把当前墙入栈,指针后移。

代码

class Solution {
    public int trap(int[] arr) {
        Stack<Integer> s=new Stack<>();
        int i=0;
        int res=0;
        while(i<arr.length)
        {
            while(!s.isEmpty()&&arr[i]>arr[s.peek()])
            {
                int cur=s.pop();
                if(s.isEmpty()) break;
                int p=s.peek();
                res+=(i-p-1)*(Math.min(arr[i],arr[p])-arr[cur]);
                
            }
     
            s.add(i++);
        }
        return res;
    }
}

时间复杂度:虽然 while 循环里套了一个 while 循环,但是考虑到每个元素最多访问两次,入栈一次和出栈一次,所以时间复杂度是 O(n)。

空间复杂度:O(n)栈的空间。