【每日一题Day274】LC42接雨水 | 单调栈

简介: 【每日一题Day274】LC42接雨水 | 单调栈

接雨水【LC42】[面试常见]

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

按列求贡献:枚举

首先确定按行计算雨水,还是按列确定雨水

  • 按行计算:按列计算:找每个柱子左右两边第一个大于该柱子高度的柱子
    第一列和最后一列不能容纳雨水,其他列可以容纳的雨水量宽度固定为1,高度取决于min(该列左侧最高的柱子,该列右侧最高的柱子)- 该列的高度

  • 代码
class Solution {
    public int trap(int[] height) {
        int res = 0;
        int lens = height.length;
        for (int i = 1; i < lens - 1; i++){
            int maxL = height[i];
            int maxR = height[i];// Math.min(maxL,maxR) - height[i] 一定大于0
            for (int j = 0; j < i; j++){
                maxL = Math.max(maxL,height[j]);
            }
            for (int k = i + 1; k < lens; k++){
                maxR = Math.max(maxR,height[k]);
            }
            res += Math.min(maxL,maxR) - height[i];
        }
        return res;
    }
}
class Solution {
    public int trap(int[] height) {
        int res = 0;
        int lens = height.length;
        for (int i = 1; i < lens - 1; i++){
            int maxL = 0;
            int maxR = 0;// h可能小于0
            for (int j = 0; j < i; j++){
                maxL = Math.max(maxL,height[j]);
            }
            for (int k = i + 1; k < lens; k++){
                maxR = Math.max(maxR,height[k]);
            }
            int h = Math.min(maxL,maxR) - height[i];
            if (h > 0){
                res += h;
            }
        }
        return res;
    }
}

image.png

按列求贡献:动态规划

使用dp数组记录,每列左边柱子的最高高度和右边柱子的最高高度

class Solution {
    public int trap(int[] height) {
        int res = 0;
        int lens = height.length;
        int[] maxL = new int[lens];
        maxL[0] = height[0];
        int[] maxR = new int[lens];
        maxR[lens-1] = height[lens-1];
        for (int i = 1; i < lens; i++){
            maxL[i] = Math.max(maxL[i-1],height[i]);
        }
        for (int i = lens - 2; i >= 0; i--){
            maxR[i] = Math.max(maxR[i+1],height[i]);
        }
        for (int i = 1; i < lens-1; i++){
            res += Math.min(maxL[i],maxR[i]) - height[i];
        }
        return res;
    }
}

image.png

按行求:单调栈

  • 思路
    使用单调递增栈记录,凹槽处的左边高度和右边高度,按行计算雨水体积。当当前高度大于栈顶元素时,计算雨水体积,高度为左右边高度较小值-凹槽高度,宽度为右边下标-左边下标-1


  • 单调栈里元素是递增呢? 还是递减呢?
    递增,注意一下顺序为 从栈头到栈底的顺序
  • 使用单调栈主要有三个判断条件。
  • 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
    直接把这个元素压入栈
  • 当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
  • 入栈或者不入栈,之前元素弹出或者不弹出不影响结果,(因为遇到相同高度的柱子时,需要使用最右边的柱子以及最左边的柱子计算宽度,左边为相同高度柱子时,计算结果为0)
  • 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况
    此时出现凹槽,可以容纳雨水,计算雨水容量,再入栈
  • 取栈顶元素,将栈顶元素弹出,下标即为mid,这个位置为凹槽的底部
  • 再取栈顶元素,下标为st.peekFirst(),这个位置为凹槽的左侧
  • 当前遍历元素为凹槽的右边位置,下标为i
  • 雨水高度为min(凹槽左边高度, 凹槽右边高度) - 凹槽底部高度
    int h = min(height[st.peekFirst()], height[i]) - height[mid];
  • 雨水宽度为 凹槽右边的下标 - 凹槽左边的下标 - 1
  • int w = i - st.peekFirst() - 1 ;
  • 雨水的体积为h * w
  • 实现
    2023/7/23
class Solution {
    public int trap(int[] height) {
        // 贡献:每个位置能积累的水量为min(左边最大,右边最大)-柱子高度
        // int n = height.length;
        // int[] left = new int[n], right = new int[n];
        // for (int i = 0; i < n - 1; i++){
        //     left[i + 1] = Math.max(left[i], height[i]);
        //     right[n - i - 2] = Math.max(right[n - i - 1], height[n - i - 1]);
        // }
        // int res = 0;
        // for (int i = 0; i < n; i++){
        //     res += Math.max(Math.min(right[i], left[i]) - height[i], 0);
        // }
        // return res;
        // 单调递增栈【栈顶->栈底】:遇到大于栈顶的柱子,弹出计算雨水量;
        Deque<Integer> st = new LinkedList<>();
        int n = height.length, res = 0;
        for (int i = 0; i < n; i++){
            while (!st.isEmpty() && height[st.peekLast()] <= height[i]){
                int mid = st.pollLast();
                if (st.isEmpty()){
                    break;
                }
                int left = st.peekLast();
                int w = i - left - 1;
                int h = Math.min(height[left], height[i]) - height[mid];
                res += w * h;
            }
            st.addLast(i);
        }
        return res;
    }
}

image.png

目录
相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
166 9
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
30 1
|
19天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
42 5
|
1月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
1月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
1月前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
51 4
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
26天前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
43 0
|
2月前
数据结构(栈与列队)
数据结构(栈与列队)
23 1
|
2月前
【数据结构】-- 栈和队列
【数据结构】-- 栈和队列
19 0