寒假CS精英挑战营_算法部分_第0周_直方图中最大的矩形_笔记

一.题目描述

问题描述

有一个直方图,横轴长度为 n,第 i 列的高度为 h[i]。
请你求出在这个直方图中面积最大的子矩阵。

输入格式

第一行一个正整数 n。
第二行 n 个用空格隔开的非负整数,依次描述 h[1],h[2],…,h[n]。

输出格式

输出一行一个数,表示最大面积。

样例输入

5
2 3 3 3 2

样例输出

10

二.几种解题思路

1.暴力

枚举每一条可能的底边,计算出高,求出面积最大值,复杂度 O ( n 3 ) O(n^3) O(n3)

2.暴力算法邓公版

1)定义曲线上每个极小值点为一个卡位点,记为k(pivot)
2)每个卡位点左右两侧都有挡住他的点(比卡位点小的地方),记为 i k i_k ik j k j_k jk,此时围城的矩形的面积为一个极大值,面积为 H [ k ] ∗ ( j k − i k − 1 ) H[k]*(j_k-i_k-1) H[k](jkik1)
3)枚举每一个卡位点,得到一系列极大值,即可找出矩形的最大值,该算法复杂度 O ( n 2 ) O(n^2) O(n2)

3.分治算法

定义一个区间最低lo,最高hi,卡位点k。
根据卡位点k,将一个区间划分为左右两侧,返回左区间最大值,右区间最大值和当前区间的值,这三个值中的最大值,递归调用即可得到结果

复杂度分析:

T ( n ) = { 2 ∗ T ( n 2 ) best T ( n − 1 ) worst  + O ( n ) T(n) = \begin{cases} 2*T(\frac n2) &\text{best} \\ T(n-1) &\text{worst } \end{cases}+O(n) T(n)={2T(2n)T(n1)bestworst +O(n)因此,最优时达到了O(nlogn),但是最坏情况为 O ( n 2 ) O(n^2) O(n2)

4.分治+查找表

做一个查找表(look up table),记录每一个区间中的最大值

复杂度分析:

查找: O ( 1 ) O(1) O(1)
构造: O ( n 2 ) O(n^2) O(n2)
存储: O ( n 2 ) O(n^2) O(n2)
构造和存储太复杂,不可取!

5.分治+线段树

查找: O ( l o g n ) O(logn) O(logn)
构造: O ( n l o g n ) O(nlogn) O(nlogn)
存储: O ( n ) O(n) O(n)
通过线段树,分治算法被优化到了O(nlogn)

6.单调栈

从左到右枚举直方图的每一列
维护一个栈底到栈顶高度单调上升的栈
若下一列小于栈顶,则弹出栈顶并更新答案
若下一列大于等于栈顶,则将该列压入栈

三.单调栈

int getAnswer(int n, int *height) {  
    int ans = 0;
    stack<int> mystack;//一个单调栈
    mystack.push(0);//height[0]=0,边界
    //循环到n+1,因为height[n+1]=0,边界
    for (int i = 1; i <= n+1; ++i)
    {
        while (!mystack.empty()&&height[mystack.top()]>height[i]) {
         int nowHeight = height[mystack.top()];
         mystack.pop();
         int L = mystack.empty() ? -1 : mystack.top();
         ans = max(ans, nowHeight*(i-L-1));
     }
     mystack.push(i);
    }
    return ans;
   }

难顶

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值