LeetCode100 42.接雨水

这题本质就是算每一个柱子上能存多少水,全部累加;

单调栈

单调栈与下面两个是不一样的思路,但是性能又不如下面

单调栈是按层(横着一层一层)算水。

栈里存下标,并且保证从栈底到栈顶高度递减。你可以把栈想成一堵正在往左墙堆的墙,墙是越堆越低的。

遇到当前柱子比栈顶高时,说明栈顶那根柱子(mid)左右两边都有更高的墙把它夹住了,它上面就能存水:

复制代码
class Solution {
    public int trap(int[] height) {
        Stack<Integer> stack = new Stack<>();
        int res = 0;
        for (int i = 0; i < height.length; i++) {
            // 当前柱子比栈顶高,栈顶形成凹槽,可以积水
            while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
                int mid = stack.pop();          // 凹槽底部柱子
                if (stack.isEmpty()) break;    // 左边没有挡板,接不住水
                int l = stack.peek();           // 左边界柱子下标
                int h = Math.min(height[l], height[i]) - height[mid]; // 积水高度
                int w = i - l - 1;              // 积水宽度
                res += h * w;                   // 累加这一层的水
            }
            stack.push(i);                      // 当前柱子入栈
        }
        return res;
    }
}

动态规划

对于每个位置 i,它能接的雨水取决于 min(左边最高柱子, 右边最高柱子) - heighti

所以用一个数组记录左最高 另一个记录有最高就可以了

复制代码
class Solution {
    public int trap(int[] height) {
        int n = height.length;
        int[] maxl = new int[n];
        int[] maxr = new int[n];
        maxl[0] = height[0];
        for (int i = 1; i < n; i++) {
            maxl[i] = Math.max(maxl[i - 1], height[i]);
        }
        maxr[n - 1] = height[n - 1];
        for (int i = n - 2; i >= 0; i--) {
            maxr[i] = Math.max(maxr[i + 1], height[i]);
        }
        // 每个位置积水 = min(左最高, 右最高) - 当前柱子高度
        int res = 0;
        for (int i = 0; i < n; i++) {
            res += Math.min(maxl[i], maxr[i]) - height[i];
        }
        return res;
    }
}

双指针解法

当前位置蓄水量 = min (左边最高,右边最高) - 当前柱子高度,如果结果 <=0 就存不了水,加 0

复制代码
class Solution {
    public int trap(int[] height) {
        int l = 0;
        int r = height.length - 1;
        int maxl = 0;
        int maxr = 0;
        int sumwater = 0;
        while (l != r) {
            if (height[l] < height[r]) {
                // 左边当前柱子更矮,水位由左边已经见过的最高柱子maxl决定
                if (height[l] < maxl) {
                    sumwater += maxl - height[l];  // 当前柱子比左最高矮,能存水
                } else {
                    maxl = height[l];              // 当前柱子更高,更新左最高,存不了水
                }
                l++;
            } else {
                // 右边当前柱子更矮,水位由右边已经见过的最高柱子maxr决定
                if (height[r] < maxr) {
                    sumwater += maxr - height[r];  // 当前柱子比右最高矮,能存水
                } else {
                    maxr = height[r];              // 当前柱子更高,更新右最高,存不了水
                }
                r--; 
            }
        }
        return sumwater;
    }
}

时间复杂度: O(N)

空间复杂度: O(1)

相关推荐
枫子有风1 小时前
卡码网盘项目深挖
java·redis·jwt·es·pgvector
郭小李1 小时前
springmvc 拦截器
java·开发语言·前端
大风起兮云飞扬丶1 小时前
Java——日期类
java·开发语言
Wang's Blog1 小时前
Java 项目实战:交友项目 - 联系人管理需求分析
java·开发语言·交友
lazy H1 小时前
【计算机网络】第 13 篇:NAT 和端口映射是什么?为什么本地服务外网访问不了?
java·网络·网络协议·学习·计算机网络·408
学到老活到老2 小时前
第 22 集:Filter、Interceptor、AOP 都能拦截,为什么不能互换?
java·后端·spring
sun03222 小时前
【JDK 动态代理】 和 【CGLIB 代理】对比
java·数据库·sql
文丑颜不良啊2 小时前
LeetCode1261~1280题目解析
java·leetcode
郭小李2 小时前
spring 中的 @EnableWebMvc注解和WebMvcConfigurer接口
java·后端·spring