单调栈——从“找下一个更大的“到柱状图中的最大矩形

本文是「数据结构与算法面试精讲」系列第21篇。前20篇覆盖了链表、二叉树、回溯、DP、哈希表、BST、滑动窗口、栈队列、二分查找、双指针、排序、图、前缀和、堆、Trie、并查集、LRU Cache等全部常见数据结构和算法。第21篇,我们来聊一个"栈的进阶用法"------单调栈。它不是一个全新的数据结构,而是一种"模式",一旦掌握,就能解决一大类问题。


一、单调栈基本原理

单调栈的核心思想是:维护一个栈,栈内元素保持单调递增或单调递减,在遍历过程中,当遇到破坏单调性的元素时,触发"结算"操作。

单调递增栈 vs 单调递减栈

类型 栈内顺序 解决的问题 典型题目
单调递减栈 栈底到栈顶递减 找下一个更大元素 739. 每日温度
单调递增栈 栈底到栈顶递增 找下一个更小元素 84. 柱状图最大矩形

核心模板

复制代码
// 单调递减栈------找下一个更大元素
for (int i = 0; i < nums.length; i++) {
    while (!stack.isEmpty() && nums[i] > nums[stack.peek()]) {
        int idx = stack.pop();
        // 结算:nums[i] 是 nums[idx] 的下一个更大元素
    }
    stack.push(i);
}

时间复杂度

  • 每个元素入栈一次、出栈最多一次

  • O(n),比暴力法的 O(n²) 大幅优化


二、739. 每日温度(Easy)

问题描述

给定一个温度数组,返回需要等多少天才会出现更高的温度。

复制代码
输入: temperatures = [73, 74, 75, 71, 69, 72, 76, 73]
输出: [1, 1, 4, 2, 1, 1, 0, 0]

Java实现

复制代码
class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int n = temperatures.length;
        int[] result = new int[n];
        Deque<Integer> stack = new ArrayDeque<>();

        for (int i = 0; i < n; i++) {
            while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) {
                int idx = stack.pop();
                result[idx] = i - idx;
            }
            stack.push(i);
        }
        return result;
    }
}

Python实现

复制代码
class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        n = len(temperatures)
        result = [0] * n
        stack = []
        for i in range(n):
            while stack and temperatures[i] > temperatures[stack[-1]]:
                idx = stack.pop()
                result[idx] = i - idx
            stack.append(i)
        return result

C++实现

复制代码
class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        int n = temperatures.size();
        vector<int> result(n, 0);
        stack<int> st;
        for (int i = 0; i < n; i++) {
            while (!st.empty() && temperatures[i] > temperatures[st.top()]) {
                int idx = st.top(); st.pop();
                result[idx] = i - idx;
            }
            st.push(i);
        }
        return result;
    }
};

三、84. 柱状图中最大的矩形(Hard)

问题描述

给定一个数组,表示柱状图中每个柱子的高度,找出最大矩形面积。

复制代码
输入: heights = [2, 1, 5, 6, 2, 3]
输出: 10  (由高度5和6组成的5x2矩形)

思路推导

核心洞察:对每个柱子,以它的高度为高,向左向右找到第一个比它矮的柱子,左右边界之间的宽度就是它的最大宽度。

用单调递增栈:遍历时,当当前柱子高度小于栈顶,说明栈顶的右边界找到了,开始结算。

Java实现(哨兵优化)

复制代码
class Solution {
    public int largestRectangleArea(int[] heights) {
        int n = heights.length;
        int[] h = new int[n + 2];
        System.arraycopy(heights, 0, h, 1, n);
        h[0] = 0;
        h[n + 1] = 0;

        Deque<Integer> stack = new ArrayDeque<>();
        stack.push(0);
        int maxArea = 0;

        for (int i = 1; i <= n + 1; i++) {
            while (h[i] < h[stack.peek()]) {
                int height = h[stack.pop()];
                int width = i - stack.peek() - 1;
                maxArea = Math.max(maxArea, height * width);
            }
            stack.push(i);
        }
        return maxArea;
    }
}

Python实现

复制代码
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        h = [0] + heights + [0]
        n = len(h)
        stack = [0]
        max_area = 0
        for i in range(1, n):
            while h[i] < h[stack[-1]]:
                height = h[stack.pop()]
                width = i - stack[-1] - 1
                max_area = max(max_area, height * width)
            stack.append(i)
        return max_area

四、单调栈问题分类

题目 难度 类型 核心思路
739. 每日温度 Easy 下一个更大元素 单调递减栈
496. 下一个更大元素 I Easy 下一个更大元素 单调递减栈 + HashMap
503. 下一个更大元素 II Medium 下一个更大元素(循环数组) 单调递减栈 + 遍历两轮
84. 柱状图中最大矩形 Hard 最大面积 单调递增栈 + 哨兵
85. 最大矩形 Hard 最大面积(二维) 逐行化为84题
42. 接雨水 Hard 面积计算 单调栈/双指针

五、总结

单调栈的核心公式

复制代码
暴力法 O(n²) + 单调栈优化 = O(n)

判断什么时候用单调栈

  1. 问题涉及"找下一个更大/更小元素"

  2. 暴力法需要两层循环

  3. 内层循环的"终止条件"具有单调性

面试答题顺序

  1. 先讲暴力法,分析为什么慢

  2. 引入单调栈,画图演示

  3. 写代码实现

  4. 分析复杂度


参考资料

  1. LeetCode 739. Daily Temperatures --- 官方题解

  2. LeetCode 84. Largest Rectangle in Histogram --- 官方题解

  3. 《算法竞赛进阶指南》------单调栈章节

相关推荐
oradh7 小时前
Oracle Undo问题总结(ORA-600 [4xxx] 系列错误)
数据库·oracle
达梦数据7 小时前
DMDRS辅助表生成规则与作用
数据库·oracle
‎ദ്ദിᵔ.˛.ᵔ₎7 小时前
MySQL 表约束
数据库·mysql
Doris__HE7 小时前
【元脑服务器NF5476G7-NF5476M7技术规格分享】
运维·服务器·网络·数据库·性能优化
汉克老师7 小时前
GESP2026年9月认证C++三级( 第三部分编程题(2、分割字符串))精讲
c++·gesp·小学生·学c++编程
估值探索者8 小时前
【Python量化系统工程化 #08】关了 SSH 就停?systemd 让脚本开机自启 + 异常自动拉起
java·c++·人工智能·分类·数据挖掘
西柚研究生1234568 小时前
论文分析17:YOLOv11_UAVNet:无人机航拍图像专用目标检测算法
人工智能·python·深度学习·算法·目标检测
天若有情6738 小时前
C++花式魔改!手写头文件复刻Java语法,彻底打破编码思维定式
java·c++·语言做语言·jac++
qq_199886878 小时前
第7板块·第3节:CUTLASS 的 GEMM 实现与优化策略
c++·人工智能·gpu算力·cuda
hetao17338378 小时前
2026-09-17 hetao1733837 的刷题记录
c++·算法