信奥题解:最大矩形纸片——单调栈的特点及示例分析

本文先介绍什么是单调栈,然后用一个简单的示例进行分析以加强理解,最后以十四届蓝桥杯省赛第四题"最大矩形纸片"为案例,分析多种不同的实现。

什么是单调栈

单调栈是一种常用的数据结构,主要用于解决需要维护一组元素的单调性问题,尤其是在求解“下一个更大元素”、“下一个更小元素”这类问题时,效率非常高,通常可以在线性时间内完成。单调栈的特点如下:

1. 单调性

单调栈可以分为两种类型:

  • 单调递增栈:栈中的元素从栈底到栈顶保持递增,即越靠近栈顶的元素越大。
    • 每当一个新元素小于栈顶元素时,栈顶元素会被弹出。
  • 单调递减栈:栈中的元素从栈底到栈顶保持递减,即越靠近栈顶的元素越小。
    • 每当一个新元素大于栈顶元素时,栈顶元素会被弹出。

注意:这里的“递增”或“递减”通常是指栈中存储的实际元素的值,但在某些问题中,也可以与这些元素的索引等信息结合使用。

2. 动态维护区间信息

单调栈擅长处理动态维护区间内的某种极值问题,例如:

  • 找到数组中每个元素的最近的比它大或比它小的元素
  • 在不使用嵌套循环的情况下高效处理“下一更大/更小元素”的问题。

由于栈中的元素始终保持某种单调性,当遍历到一个新的元素时,可以通过不断弹出栈顶元素的方式来找到符合条件的区间边界。

3. 时间复杂度

单调栈的时间复杂度是 O(n)。虽然每个元素会被压入和弹出栈,但每个元素最多只会进栈和出栈一次,因此整体操作是线性的,非常高效。

4. 应用场景

单调栈广泛应用于很多经典的算法问题中,特别是需要快速找到某个元素在特定方向上的最大或最小值的情况。常见的应用包括:

  • 下一个更大元素问题(Next Greater Element)
  • 下一个更小元素问题(Next Smaller Element)
  • 直方图中最大矩形问题(基于单调栈找出最大的矩形面积)
  • 滑动窗口极值问题(滑动窗口中找出最大或最小值)

5. 栈操作与逻辑

单调栈的操作逻辑通常包括以下几个步骤:

  1. 遍历数组:按顺序遍历数组的每一个元素。
  2. 弹出栈顶元素:如果当前元素不符合栈的单调性(例如,对于单调递增栈,当前元素小于栈顶元素),则弹出栈顶元素,直到栈顶元素符合单调性为止。
  3. 处理弹出元素:通常在弹出栈顶元素时,可以得到一些问题的解(如弹出元素对应的最近更大或更小的元素)。
  4. 压入新元素:将当前元素压入栈,继续遍历下一个元素。

例子:单调递增栈的简单示例

假设我们需要找到数组中每个元素的下一个更大元素

vector<int> nextGreaterElement(vector<int>& nums) {
   
   
    vector<int> result(nums.size(), -1); // 初始化结果数组,默认值为 -1
    stack<int> s;  // 单调递增栈,存储元素的索引
    
    for (int i = 0; i < nums.size(); i++) {
   
   
        // 当前元素比栈顶元素大,则弹出栈顶并处理
        while (!s.empty() && nums[i] > nums[s.top()]) {
   
   
            result[s.top()] = nums[i];  // 当前元素是栈顶元素的下一个更大元素
            s.pop();
        }
        // 将当前元素的索引压入栈
        s.push(i);
    }
    
    return result;  // 返回结果数组
}

总结

单调栈的主要特点

  • 保持栈中元素的单调性(递增或递减)。
  • 高效地处理某个元素的下一个更大或更小值问题。
  • 每个元素最多入栈和出栈一次,因此时间复杂度是 O(n)。

单调栈在操作过程中通过维护栈内元素的单调性来高效解决问题。为了说明单调栈的操作过程,下面通过一个经典的“下一个更大元素”问题为例,详细展示单调栈的每一步操作。

示例分析:找出每个元素的下一个更大元素

问题描述
给定一个数组 nums,对于数组中的每个元素,找出其右侧的第一个比它大的元素。如果不存在,则返回 -1。我们可以使用单调栈来高效解决这个问题。

例如,给定数组 nums = [2, 1, 5, 3, 6],我们想找到每个元素右边的第一个更大元素:

  • 对于 2,右边第一个比 2 大的元素是 5
  • 对于 1,右边第一个比 1 大的元素是 5
  • 对于 5,右边第一个比 5 大的元素是 6
  • 对于 3,右边第一个比 3 大的元素是 6
  • 对于 6,右边没有比 6 大的元素,返回 -1

解决思路:单调递减栈

我们使用单调递减栈(栈中存储的元素从栈底到栈顶递减),在遍历过程中保持栈内元素的递减顺序。这样,当当前元素比栈顶元素大时,栈顶元素就是需要更新的元素,其下一个更大元素就是当前元素。

步骤展示

  1. 初始化栈和结果数组
    • 使用一个栈 stack 来存储元素的索引
    • 结果数组 result 初始化为 -1,表示找不到下一个更大元素的情况。
vector<int> nums = 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值