当前位置: 首页 > news >正文

单调栈 | part02

42. 接雨水 - 力扣(LeetCode)

给定 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
public int trap(int[] height) { if (height == null || height.length < 3) return 0; int result = 0; Deque<Integer> deque = new ArrayDeque<>(); deque.push(0); for (int i = 1; i < height.length; i++) { if (height[i] <= height[deque.peek()]) { deque.push(i); } else { while (!deque.isEmpty() && height[i] > height[deque.peek()]) { int index = deque.pop(); if (!deque.isEmpty()) { int left = deque.peek(); int right = i; int h = Math.min(height[left], height[right]) - height[index]; int w = right - left - 1; result += h * w; } } deque.push(i); } } return result; }

解题:

这道题的核心在于计算每一列上方能接多少雨水。使用单调栈的方法,主要关注的是横向计算雨水面积。

  • 单调栈的性质:栈中存储的是数组的下标,且这些下标对应的柱子高度是单调递减的(栈底到栈顶)。
  • 触发条件:当遇到一个比栈顶元素高的柱子时,说明形成了一个“凹槽”(由左边界、当前右边界和中间的底部组成),此时可以计算积水量。
  • 计算方式:每次弹出一个栈顶元素作为“底部”,新的栈顶元素作为“左边界”,当前遍历到的元素作为“右边界”。

积水量的计算公式

  • 底部 (index):刚刚弹出的元素,它是这一层积水的最低点。
  • 左边界 (left):弹出index后,现在的栈顶元素。它一定比index高(因为栈是递减的),且是index左边最近的高墙。
  • 右边界 (right):当前遍历到的i。它比index高(否则不会进入while循环)。
  • 有效高度h:水的高度取决于左右边界中较矮的那个,再减去底部的高度。即min(height[left], height[right]) - height[index]
  • 有效宽度w:左右边界之间的距离,不包含边界本身,即right - left - 1

84. 柱状图中最大的矩形 - 力扣(LeetCode)

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

  • 1 <= heights.length <=10^5
  • 0 <= heights[i] <= 10^4
public int largestRectangleArea(int[] heights) { if (heights == null || heights.length == 0) { return 0; } //对数组首位加0 int[] nums = new int[heights.length + 2]; nums[0] = 0; nums[nums.length - 1] = 0; for (int i = 1; i < heights.length + 1; i++) { nums[i] = heights[i - 1]; } int result = 0; Deque<Integer> deque = new ArrayDeque<>(); deque.push(0); for (int i = 1; i < nums.length; i++) { if (nums[i] > nums[deque.peek()]) { deque.push(i); } else if (nums[i] == nums[deque.peek()]) { deque.push(i); } else { while (!deque.isEmpty() && nums[i] < nums[deque.peek()]) { int mid = deque.pop(); if (!deque.isEmpty()) { int left = deque.peek(); int right = i; int h = nums[mid]; int w = right - left - 1; result = Math.max(result, h * w); } } deque.push(i); } } return result; }

解题:

我们需要先对原数组进行处理,在首尾加上0,这是为了防止后续栈操作的时候,陷入错误,比如一个递减数组,会一直入栈,而不进行矩阵统计,若是递增数组,会导致后续的元素都无法进入,也无法进行矩阵统计。所以需要加上这俩个值去预防这种问题。

我们的栈与之前的都不同,是一个递增栈,之前都是递减栈。想象你站在中间的一根柱子上(高度为 H ),你要向左右两边拉一条水平的横幅,横幅的高度必须保持在 H 。

  • 往左看
    • 如果左边的柱子比你:横幅可以搭在它上面,继续往左延伸。(没问题,通通过去)
    • 如果左边的柱子比你:横幅没法悬空,也没法把矮柱子拔高。横幅必须在这里断开。这就是左边界
  • 往右看
    • 同理,右边的柱子比你,横幅可以继续搭过去。
    • 右边的柱子比你,横幅必须断开。这就是右边界

结论
为了算出以当前高度 H能画出的最大矩形,我们需要找到左边第一个比 HH矮的右边第一个比 H矮的。这两个“矮个子”就是挡住你去路的

其他的部分与接雨水是很相似的。

http://www.jsqmd.com/news/455345/

相关文章:

  • 2D高斯泼溅实战:从零搭建几何精准的3D重建环境(附代码调试技巧)
  • MedGemma 1.5惊艳表现:对‘心电图ST段压低’的缺血/电解质/药物/伪差四维鉴别推理
  • 丹青幻境·Z-Image Atelier参数详解:画布幅宽、机缘Seed与避讳设置全解析
  • 5步完成Qwen3-ASR-0.6B部署:简单易懂的入门教程
  • C++图像处理毕设实战:从OpenCV选型到内存安全的完整技术路径
  • ElegantBook LaTeX模板:专业书籍排版解决方案与实战指南
  • Java函数冷启动优化终极手册(附JFR火焰图诊断模板+启动耗时归因SLO看板)
  • Ollama平台EmbeddingGemma-300m快速部署与API调用指南
  • bootstrap-datetimepicker:轻量级日期时间选择解决方案的技术解析与实践指南
  • 突破API付费壁垒:打造个人专属免费翻译服务
  • 基于阿里小云KWS的语音控制无人机系统
  • 从理论到实战:基于快马平台生成电商销售额预测ai学习项目
  • SenseVoice-Small ONNX与卷积神经网络结合:多模态语音情感分析
  • 逆向工程师必备:用MDL绕过游戏保护读取内存数据的完整流程(附POC代码)
  • tao-8k Embedding模型实战案例:构建中文法律文书语义检索系统
  • StructBERT模型Docker化部署进阶:使用Docker Compose编排WebUI与数据库
  • Jetson Orin NX深度学习环境配置全攻略:从JetPack到PyTorch避坑指南
  • Ostrakon-VL-8B与LSTM时间序列分析:预测菜品销量趋势
  • Wan2.1-umt5实战:基于Transformer架构的文本生成效果深度评测
  • Win11系统一键部署Qwen3教程:在星图GPU平台快速体验视觉生成
  • RK3588 Android12开机异常排查指南:如何通过log定位PMIC和DDR问题
  • GLM-OCR命令行工具开发:快速批处理图片文件夹
  • 手把手教你用SCP命令迁移Ollama模型文件(支持离线运行,含常见问题解决)
  • 新手必看:5分钟用通义千问Embedding模型,搭建开箱即用的智能问答系统
  • 可解释性:为什么 AI 说这是病毒?打破“黑盒”决策
  • OpenDataLab MinerU日志审计功能:操作追溯与安全管理
  • Testsigma实战指南:从测试困境到效能提升的自动化转型之路
  • 为什么Fortify总是误报Access Control: Database?聊聊安全工具的局限性
  • LoRA动态切换太香了!一个底座玩转多个Cosplay风格,效率翻倍
  • C# WinForm项目实战:5分钟搞定INI配置文件读写(附完整源码)