[H单调栈] lc3113. 边界元素是最大值的子数组数目(单调栈+问题转换+模板题+好题)

文章目录

    • [1. 题目来源](#1. 题目来源)
    • [2. 题目解析](#2. 题目解析)

1. 题目来源

链接:3113. 边界元素是最大值的子数组数目

2. 题目解析

单调栈问题,代码很短,看看是怎么一步步思考出来的:

  • 首先,子数组问题,可以优先考虑枚举 右端点(枚举左端点也是可以的)。枚举右端点的好处是,枚举到 rj 时,我的 li 已经被枚举过了,我只需要从 "满足条件" 的 li 中挑选出来符合的结果即可。这里的条件,实际上就是题目中的待发现的性质。
  • 对于本题,先举个例子:4, 3, 1, 2, 1 顺序枚举时,有 4,3,1,当遇见 2 时中间这个 1 是完全没有机会的,因为左边是比它大的数,右边也有个比它大的数,它已经不可能是一个子数组的边界了。
    • 所以,可以不用考虑这个 1。
    • 根据这个性质,很明显,只需要维护一个从左到右的单调栈就行了。
    • 栈内放什么元素呢?应该放的是 [数字, 数字出现的次数],因为题目要求的子数组两头是一样的数字。
    • 再发现,当我们有了单调栈,现在枚举到 x 时,x 和栈顶有三个关系。
      • x > top:直接出栈即可
      • x == top:答案累计 top 出现的次数即可,并需要将 top 的次数需要加 1。
      • x < top:入栈,次数为 1。

代码实现技巧:

  • res 初始化为 n,因为单个元素也算一种子数组。
  • 单调栈放入一个正无穷大哨兵,防止栈为空。就不用做 stk.size() 的判断了。
    • 这是一个很强的技巧哈,积累一下。

  • 时间复杂度 : O ( n ) O(n) O(n)
  • 空间复杂度 : O ( 1 ) O(1) O(1)

单调栈,未加哨兵:

cpp 复制代码
class Solution {
public:
    long long numberOfSubarrays(vector<int>& nums) {
        typedef long long LL;
        int n = nums.size();

        LL res = n;
        stack<pair<int, int>> stk;
        for (int i = 0; i < n; i ++ ) {
            int x = nums[i];
            while (stk.size() && stk.top().first < x) stk.pop();
            if (stk.size() && stk.top().first == x) {
                res += stk.top().second;
                stk.top().second ++ ;
                continue;
            } 

            stk.push({x, 1});
        }

        return res;
    }
};

单调栈,哨兵优化,避免判断栈是否为空:

cpp 复制代码
class Solution {
public:
    long long numberOfSubarrays(vector<int>& nums) {
        typedef long long LL;
        int n = nums.size();

        LL res = n;
        stack<pair<int, int>> stk;
        stk.push({1e9, 0}); // 添加哨兵元素,保证单调栈不为空
        for (int i = 0; i < n; i ++ ) {
            int x = nums[i];
            while (stk.top().first < x) stk.pop();
            if (stk.top().first == x)  res += stk.top().second ++ ;
            else stk.push({x, 1});
        }

        return res;
    }
};
相关推荐
NAGNIP4 小时前
大模型框架性能优化策略:延迟、吞吐量与成本权衡
算法
美团技术团队5 小时前
LongCat-Flash:如何使用 SGLang 部署美团 Agentic 模型
人工智能·算法
Fanxt_Ja10 小时前
【LeetCode】算法详解#15 ---环形链表II
数据结构·算法·leetcode·链表
侃侃_天下10 小时前
最终的信号类
开发语言·c++·算法
茉莉玫瑰花茶10 小时前
算法 --- 字符串
算法
博笙困了10 小时前
AcWing学习——差分
c++·算法
NAGNIP10 小时前
认识 Unsloth 框架:大模型高效微调的利器
算法
NAGNIP10 小时前
大模型微调框架之LLaMA Factory
算法
echoarts10 小时前
Rayon Rust中的数据并行库入门教程
开发语言·其他·算法·rust
Python技术极客10 小时前
一款超好用的 Python 交互式可视化工具,强烈推荐~
算法