【力扣】42. 接雨水 <模拟、双指针、单调栈>

【力扣】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

提示:

n == height.length

1 <= n <= 2 * 1 0 4 10^4 104

0 <= heighti <= 1 0 5 10^5 105

题解

暴力

按照列来计算的话,宽度一定是1,把每一列的雨水的高度求出来即可。

每一列雨水的高度,取决于该列左侧最高的柱子和右侧最高的柱子中最矮的那个柱子的高度。
min(左边柱子的最高高度,记录右边柱子的最高高度) - 当前柱子高度
min(lHeight, rHeight) - height

java 复制代码
public class Solution {
    public int trap(int[] height) {
        int sumWater = 0;

        for (int i = 0; i < height.length; i++) {
            // 第一个柱子和最后一个柱子不接雨水
            if (i==0 || i== height.length - 1) {
                continue;
            }

            // 记录右边柱子的最高高度
            int rHeight = height[i];
            // 记录左边柱子的最高高度
            int lHeight = height[i];

            // 求左边最高柱子
            for (int l = i-1; l >= 0; l--) {
                if(height[l] > lHeight) {
                    lHeight = height[l];
                }
            }
            // 求右边最高柱子
            for (int r = i+1; r < height.length; r++) {
                if (height[r] > rHeight) {
                    rHeight = height[r];
                }
            }

            //每一列雨水的高度,取决于,该列左侧最高的柱子和右侧最高的柱子中 最矮的那个柱子的高度。
            int h = Math.min(lHeight, rHeight) - height[i];
            if (h > 0) {
                sumWater += h;
            }
        }
        return sumWater;
    }
}

双指针

每到一个柱子都向两边遍历一遍,这其实是有重复计算的,为了得到两边的最高高度,使用了双指针来遍历。把每一个位置的左边最高高度记录在一个数组上(maxLeft),右边最高高度记录在一个数组上(maxRight),这样就避免了重复计算。

当前位置,左边的最高高度是前一个位置的左边最高高度和本高度的最大值。当前位置,右边的最高高度是前一个位置的右边最高高度和本高度的最大值。

java 复制代码
public class Solution {
    public int trap(int[] height) {
        // 每到一个柱子都向两边遍历一遍,这其实是有重复计算
        // 把每一个位置的左边最高高度记录在一个数组上(maxLeft),右边最高高度记录在一个数组上(maxRight)
        int[] maxLeft = new int[height.length];
        int[] maxRight = new int[height.length];

        // 记录每个柱子左边柱子最大高度
        maxLeft[0] = height[0];
        for (int i = 1; i < height.length; i++) {
            //当前位置,左边的最高高度是前一个位置的左边最高高度和本高度的最大值
            maxLeft[i] = Math.max(height[i], maxLeft[i - 1]);
        }

        // 记录每个柱子右边柱子最大高度
        maxRight[height.length - 1] = height[height.length - 1];
        for (int i = height.length - 2; i >= 0; i--) {
            //当前位置,右边的最高高度是前一个位置的右边最高高度和本高度的最大值
            maxRight[i] = Math.max(height[i], maxRight[i + 1]);
        }

        // 求和
        int sumWater = 0;
        for (int i = 0; i < height.length; i++) {
            // 第一个柱子和最后一个柱子不接雨水
            if (i==0 || i== height.length - 1) {
                continue;
            }

            int h = Math.min(maxLeft[i], maxRight[i]) - height[i];
            if (h > 0) {
                sumWater += h;
            }
        }
        return sumWater;
    }
}

单调栈

单调栈是按照行方向 来计算雨水。

栈头(元素从栈头弹出)到栈底的顺序应该是从小到大 的顺序。因为一旦发现添加的柱子高度大于栈头元素了,此时就出现凹槽了,栈头元素就是凹槽底部的柱子,栈头第二个元素就是凹槽左边的柱子,而添加的元素就是凹槽右边的柱子。

遇到相同高度的柱子:要求宽度的时候 如果遇到相同高度的柱子,需要使用最右边的柱子来计算宽度。

java 复制代码
import java.util.Stack;

public class Solution {
    public int trap(int[] height){
        int sumWater = 0;

        if (height.length <= 2) {
            return 0;
        }

        Stack<Integer> stack = new Stack<>();
        stack.push(0);

        for (int index = 1; index < height.length; index++){
            //情况一
            if (height[index] < height[stack.peek()]){
                stack.push(index);
            }
            //情况二
            else if (height[index] == height[stack.peek()]){
                // 因为相等的相邻墙,左边一个是不可能存放雨水的,所以pop左边的index, push当前的index
                stack.pop();
                stack.push(index);
            }
            //情况三
            else{
                while (!stack.isEmpty() && (height[index] > height[stack.peek()])){
                    int mid = stack.peek();
                    stack.pop();

                    if (!stack.isEmpty()){
                        int left = stack.peek();

                        //长就是通过柱子的高度来计算
                        int h = Math.min(height[left], height[index]) - height[mid];
                        //宽是通过柱子之间的下标来计算
                        int w = index - left - 1;
                        int area = h * w;

                        if (area > 0) {
                            sumWater += area;
                        }
                    }
                }
                stack.push(index);
            }
        }
        return sumWater;
    }
}
相关推荐
信誓旦旦的程序猿7 小时前
【Python 量化取数指南 #09】Python 拿港股通数据:港股通成交与港股财报实测
java·python·股票数据api·股票数据·股票数据api接口·股票api数据接口·股票量化数据api
小程序设计7 小时前
本科毕设避坑|大数据 / 单片机物联网 / 网络工程 / PLC / 机械设计选题与落地心得
java·hive·hadoop·单片机
UIU1147 小时前
递归算法与汉诺塔
c++·学习·算法·c#·递归
卓怡学长7 小时前
w206基于SpringBoot的社区团购小程序设计与实现
java·spring boot·spring·intellij-idea
IT枫斗者枫哥13 小时前
MyBatis一对多分页:LIMIT 20,为什么凑不齐20个订单?
java·数据库
代码方舟13 小时前
Java数据工程:利用天远全网运营商三要素优化线上实名认证合规体验
java·人工智能
BBmmo13 小时前
我的 Java 学习笔记 · 第 7 篇:泛型与通配符
java
独泪了无痕13 小时前
Hutool之RandomUtil:随机数生成的终极利器
java·后端
用户9799848071813 小时前
200 行代码写一个能跑的 AI Agent:不依赖任何框架,只靠 tool-calling 原理
算法
花开路口13 小时前
深入理解 Java/Kotlin 协变与逆变
java·kotlin