单调栈与堆的经典应用:柱状图最大矩形 & 数组第 K 大元素深度解析

目录

[一、柱状图中最大的矩形(LeetCode 84・困难)](#一、柱状图中最大的矩形(LeetCode 84・困难))

题目描述

解题思路

核心思想

[Java 代码实现(标准单调栈版)](#Java 代码实现(标准单调栈版))

复杂度分析

核心知识点总结

[二、数组中的第 K 个最大元素(LeetCode 215・中等)](#二、数组中的第 K 个最大元素(LeetCode 215・中等))

题目描述

解题思路

核心思想(小顶堆)

[Java 代码实现(小顶堆版)](#Java 代码实现(小顶堆版))

复杂度分析

核心知识点总结

三、两道题的核心对比与联系

核心联系


今天我们来拆解两道算法面试高频题:柱状图中最大的矩形 (单调栈难题)和数组中的第 K 个最大元素 (堆的经典应用)。这两道题分别代表了单调栈两大核心数据结构的标杆应用,吃透它们能帮你彻底掌握这两种结构的灵活使用,是算法面试的必考点。


一、柱状图中最大的矩形(LeetCode 84・困难)

题目描述

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例:

plaintext

复制代码
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

输入:heights = [2,4]
输出:4

解题思路

这道题的核心是找到每个柱子能扩展的最大左右边界 ,从而计算以该柱子为高的最大矩形面积。暴力法时间复杂度为 O(n2),而单调栈可以将时间复杂度优化到 O(n)。

核心思想
  1. 维护一个单调递增栈:栈中存储柱子的下标,保证栈中下标对应的高度始终递增。
  2. 遍历数组,找左右边界
    • 对于当前柱子 i,若栈顶柱子高度 heights[stack.peek()] >= heights[i],说明栈顶柱子的右边界 就是 i
    • 弹出栈顶下标 top,计算以 heights[top] 为高的最大矩形面积:
      • 左边界为新的栈顶下标 left = stack.peek()(若栈空则为 -1
      • 宽度为 i - left - 1
      • 面积为 heights[top] * 宽度
    • 若栈顶高度小于当前高度,将 i 压入栈中。
  3. 处理栈中剩余元素 :遍历结束后,栈中剩余柱子的右边界为数组长度 n,重复上述计算过程。
  4. 最终返回最大面积

Java 代码实现(标准单调栈版)

java

运行

复制代码
import java.util.Stack;

public class LargestRectangleInHistogram {
    public int largestRectangleArea(int[] heights) {
        int n = heights.length;
        int maxArea = 0;
        // 栈中存储柱子下标,维护单调递增
        Stack<Integer> stack = new Stack<>();

        for (int i = 0; i <= n; i++) {
            // 用0作为哨兵,处理栈中剩余元素
            int currentHeight = (i == n) ? 0 : heights[i];
            // 当前高度小于栈顶高度,弹出并计算面积
            while (!stack.isEmpty() && heights[stack.peek()] >= currentHeight) {
                int top = stack.pop();
                int height = heights[top];
                // 左边界:栈空则为-1,否则为栈顶下标
                int left = stack.isEmpty() ? -1 : stack.peek();
                // 宽度 = 右边界(i) - 左边界(left) - 1
                int width = i - left - 1;
                maxArea = Math.max(maxArea, height * width);
            }
            stack.push(i);
        }

        return maxArea;
    }
}

复杂度分析

  • 时间复杂度:O(n),每个下标入栈 / 出栈最多一次,总操作次数为 O(n)
  • 空间复杂度:O(n),最坏情况(严格递增)栈的大小为 O(n)

核心知识点总结

  1. 单调递增栈的作用:快速找到每个柱子的左右边界,避免暴力遍历
  2. 哨兵优化 :在数组末尾补 0,统一处理栈中剩余元素,简化代码逻辑
  3. 边界计算 :左边界为栈顶下标(栈空则为 -1),右边界为当前下标,宽度为 右-左-1

二、数组中的第 K 个最大元素(LeetCode 215・中等)

题目描述

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例:

plaintext

复制代码
输入: [3,2,1,5,6,4], k = 2
输出: 5

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

解题思路

这道题有两种经典解法:小顶堆 (时间复杂度 O(nlogk))和快速选择 (时间复杂度 O(n),平均情况),这里重点讲解面试最常用的小顶堆解法。

核心思想(小顶堆)
  1. 维护一个大小为 k 的小顶堆 :堆顶始终是当前堆中的最小值(即前 k 大元素中的最小值)。
  2. 遍历数组
    • 若堆大小小于 k,直接将元素入堆;
    • 若堆大小等于 k,比较当前元素与堆顶:
      • 若当前元素大于堆顶,弹出堆顶,将当前元素入堆;
      • 否则跳过。
  3. 遍历结束后,堆顶元素即为第 k 大元素

Java 代码实现(小顶堆版)

java

运行

复制代码
import java.util.PriorityQueue;

public class KthLargestElementInArray {
    public int findKthLargest(int[] nums, int k) {
        // 小顶堆,默认自然排序
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();

        for (int num : nums) {
            if (minHeap.size() < k) {
                minHeap.offer(num);
            } else if (num > minHeap.peek()) {
                minHeap.poll();
                minHeap.offer(num);
            }
        }

        return minHeap.peek();
    }
}

复杂度分析

  • 时间复杂度:O(nlogk),每个元素入堆 / 出堆的时间复杂度为 O(logk),遍历数组时间为 O(n)
  • 空间复杂度 :O(k),堆的大小为 k

核心知识点总结

  1. 小顶堆的优势:空间复杂度低(仅需 O(k)),适合处理海量数据(如流式数据)
  2. 堆的选择 :求第 k 大用小顶堆,求第 k 小用大顶堆
  3. 快速选择拓展:基于快速排序的分治思想,平均时间复杂度 O(n),最坏 O(n2),适合面试加分

三、两道题的核心对比与联系

表格

题目 核心目标 数据结构 核心逻辑
柱状图中最大的矩形 找每个柱子的最大左右边界,计算最大面积 单调递增栈 维护栈的单调性,快速定位边界,优化时间复杂度
数组中的第 K 个最大元素 找数组中第 K 大的元素 小顶堆 维护大小为 k 的小顶堆,堆顶即为第 K 大元素

核心联系

两道题分别代表了单调栈两大核心数据结构的经典应用:

  • 单调栈:解决「找左右边界、下一个更大 / 更小元素」等序列问题,时间复杂度 O(n)
  • :解决「TopK、优先级队列」等问题,时间复杂度 O(nlogk),空间复杂度低
相关推荐
Strugglingler2 小时前
Python学习记录
开发语言·python
Dfreedom.2 小时前
Scikit-learn 全景解读:机器学习的“瑞士军刀”
python·机器学习·scikit-learn
长乐无暇2 小时前
第18天:for 循环与 range()
后端·python
lkforce2 小时前
MiniMind学习笔记--安装部署
笔记·python·学习·minimind
Cachel wood2 小时前
Macbook M4 pro本地部署大模型|Ollama+Gemma4/Qwen3.5
人工智能·python·自动化·llm·qwen·ollama·gemma4
whitelbwwww2 小时前
标准模板库--STL库
开发语言·c++
枫叶丹42 小时前
【HarmonyOS 6.0】ArkWeb嵌套滚动快速调度策略
开发语言·华为·harmonyos
努力学习的小廉2 小时前
Python 零基础入门——基础语法(二)
android·开发语言·python