(leetcode算法题)84. 柱状图中最大的矩形 2334. 元素值大于变化阈值的子数组

将这个问题进行转化,就能变成典型的单调栈的问题,

由于原问题中矩形的面积完全取决于其中最小矩形的高度,那么很容易想到遍历每个矩形,让每一个矩形都做一次最小矩形,看看其能够覆盖的最大宽度是多少,就能找到题目的答案。

进一步,对于第 i 号能够形成的矩形来说,我们可以将其分为两部分看待,其高度都是heightsi,

矩形的左半部分:宽度是从 i 开始往回数,大于或等于heightsi 的最大连续的区间长度

**矩形的右半部分:**宽度是从 i 开始往后数,大于或等于heightsi 的最大连续的区间长度

是不是想到901. 股票价格跨度 当时的情况了呢?但是与901不同的是,需要考虑从左遍历和从右遍历的两种情况进行相加

那么901使用了一个从栈底到栈顶单调递减栈作为辅助容器,帮助获得小于等于当前位置的连续区间长度,这里自然可以使用一个从栈底到栈顶单调递增栈作为辅助容器,帮助获得大于等于当前位置的连续区间长度

但是!!!!!!!!!!!!!!!!!!!!!!!!!!

这里需要注意更新矩形左右半部分的长度策略,我们以左半部分为例

由于采取了单调递增栈,那么当遍历到heightsi 这个高度时,我们想要更新的到底是什么,策略有两种

策略一:找到大于等于heightsi 的且离 i 最远的 那个下标,那么这个就是左半部分的端点

策略二:找到小于 heightsi 的且离 i 最近的那个下标,加一就是左半部分的端点

如果将每更新一个端点就去遍历的方案视为错,那么这两种策略一对一错,读者不妨考虑一下哪个是对的?

~

~

~

~

公布答案,策略二是对的!

策略一的反例,对于 heights = 3,6,5,7,4,8,1,0 来说,在更新 heightsi = 4 这个点的左半部分的端点时,如果想用单调递增栈找到 6,这是不可能的,因为在更新heightsi = 5 时,这个已经把6pop出栈,此时要妄想使用记录6下标的逻辑的话,就是一个暴力遍历的过程,所以此时采用策略二:

cpp 复制代码
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        stack<int> st;
        vector<int> recordleft(n, -1);
        vector<int> recordright(n, n);
        for(int i = 0; i < n; ++i){
/*利用从栈底到栈顶的单调递增栈更新*/
/*记录当前木板离他最近的那个小于当前木板高度的下标*/
            while(!st.empty() && heights[st.top()] >= heights[i]){
                st.pop();
            }
            if(!st.empty()){
                recordleft[i] = st.top();
            }
            st.push(i);
        }
        st = stack<int> ();
        for(int j = n - 1; j >= 0; --j){
            while(!st.empty() && heights[st.top()] >= heights[j]){
                st.pop();
            }
            if(!st.empty()){
                recordright[j] = st.top();
            }
            st.push(j);           
        }
        int ret = 0;
        for(int i = 0; i < n; ++i){
            int curlongestlen = recordright[i] - recordleft[i] - 1;
            ret = max(ret, curlongestlen * heights[i]);
        }
        return ret;
    }
};

这里可以采用与84题相同的算法来更新,这是因为2334也可以转换成一个相同的问题:将numsi作为连续子数组中最小的那个数,更新出连续子数组的的长度 k,然后判断 numsi / k 和threshold的关系

那么这个题和 84不是一模一样的两个题吗!!!

cpp 复制代码
class Solution {
public:
    int validSubarraySize(vector<int>& nums, int threshold) {
        int n = nums.size();
        stack<int> st;
        // vector<int> biggestminsubnumthancurnuminleft(n);
        vector<int> bmsntcinl(n);
        for(int i = 0; i < n; ++i){
            while(!st.empty() && nums[st.top()] >= nums[i]){
                st.pop();
            }
            if(!st.empty()){
                bmsntcinl[i] = st.top();
            }
            else{
                bmsntcinl[i] = -1;
            }
            st.push(i);
        }
        st = stack<int> ();
        // vector<int> biggestminsubnumthancurnuminright(n);
        vector<int> bmsntcinr(n);
        for(int j = n - 1; j >= 0; --j){
            while(!st.empty() && nums[st.top()] >= nums[j]){
                st.pop();
            }
            if(!st.empty()){
                bmsntcinr[j] = st.top();
            }
            else{
                bmsntcinr[j] = n;
            }
            st.push(j);
        }

        for(int i = 0; i < n; ++i){
            int curk = bmsntcinr[i] - bmsntcinl[i] - 1;
            // 在nums的从bmsntcinr[i] + 1 到 bmsntcinl[i] - 1的这些位置中
            // 所有数都比nums[i]大
            if(nums[i] > threshold / curk){
                return curk;
            }
        }
        return -1;
    }
};
相关推荐
余俊晖1 小时前
多模态大模型细粒度视觉理解:Vision-OPD在线策略自蒸馏技术方案概述
人工智能·深度学习·算法·多模态·opd
脚踏实地皮皮晨2 小时前
003003001_Grid控件
开发语言·windows·算法·c#·visual studio
Hi李耶2 小时前
【LeetCode】6-Z字形变换
算法·leetcode·职场和发展
XiaoYu1__2 小时前
算法进阶·其一:用SCC、Tarjan算法与缩点思想解决有向图的连通关系及2-SAT问题的拓展
算法
小O的算法实验室2 小时前
AAAI-26,全局相关性学习:通过谱图神经网络增强进化算法
神经网络·学习·算法
段一凡-华北理工大学2 小时前
AI推动工业智能化转型~系列文章07:分类与诊断算法体系:故障识别的完整工具箱
数据库·人工智能·算法·机器学习·分类·数据挖掘·高炉炼铁智能化
简信CRM2 小时前
适合离散制造中小工厂 MES 系统推荐
算法·机器学习·制造
AKA__Zas2 小时前
芝士算法(前缀和2.0)
java·数据结构·算法·leetcode·哈希算法·学习方法
皓月斯语2 小时前
B3867 [GESP202309 三级] 小杨的储蓄 题解
c++·算法·题解
半夢半醒13 小时前
[原创]《C#高级GDI+实战:从零开发一个流程图》第章:增加菱形、平行四边形、圆角矩形,文本居中显示
算法·c#·流程图