据说有这么一道题:求直方图的最大内接矩形,假设每个细条的宽度为1。
阅微客栈 » 头脑风暴
直方图的最大内接矩形
(9 posts)-
发布于 1 年 之前 #
-
这是某知名网络公司面试题,哈哈。
发布于 1 年 之前 # -
这题好难啊,是不是要特别的数学知识?坛主给点思路如何?
发布于 1 年 之前 # -
用栈来做,最后均摊的时间复杂度O(1),总体复杂度为O(n)
发布于 1 年 之前 # -
求直方图的最大内接矩形,假设每个细条的宽度为1。
初始输入为h[i],即i处的细条高度值,i的范围是[0, n-1]。
定义:三元组(i, p, q)为一个矩形,高度为h[i],宽度为q-p+1,即一个从p开始,在q结束的矩形。
max也是一个三元组,表示为(maxS, maxL, maxR)。
维护一个这样一个栈,右边为栈顶:

其中
![h[D_1] <= h[D_2] <= ... <= h[D_r]](http://zhiqiang.org/bbs/bb-cache/tex_cac0ba062118c5c77fdf0c3067eb97de.png)
且有

初始情况stack为:
(0,0,0)
置i初始为1,当i<n时进行如下循环:
(1) 栈顶对应的
![h[D_r]](http://zhiqiang.org/bbs/bb-cache/tex_0cc4decbeb0d91ada2cfc15047955c06.png)
若
![h[i] >= h[D_r]](http://zhiqiang.org/bbs/bb-cache/tex_a1114b898cc85de30a093358cc0b0c6f.png)
则把(i,i,i)推入栈,且i++;
(2) 栈顶对应的
![h[D_r]](http://zhiqiang.org/bbs/bb-cache/tex_0cc4decbeb0d91ada2cfc15047955c06.png)
若
![h[i]< h[D_r]](http://zhiqiang.org/bbs/bb-cache/tex_814048067c0526685d842dcc802cd2bd.png)
先弹出

如果
![h[D_r]*(q_r-p_r+1) > maxS](http://zhiqiang.org/bbs/bb-cache/tex_3803579cad890b841806b625c5313ace.png)
则更新max为
![(h[D_r]*(q_r-p_r+1), p_r, q_r)](http://zhiqiang.org/bbs/bb-cache/tex_e3647433dbfdc2100ddb177459146097.png)
操作完之后再分3种情况:
(2a) 栈不空,设当前栈顶为

且
![h[D_{r-1}] >= h[i]](http://zhiqiang.org/bbs/bb-cache/tex_f2c0ae7f641cefec043c5eb7d5c3671a.png)
执行如下操作:
修改栈顶为

修改后操作后i值不变。
(2b) 栈不空,设当前栈顶为

且
![h[D_{r-1}] < h[i]](http://zhiqiang.org/bbs/bb-cache/tex_abb0a2d1b8ec84943ed09d2719e625e2.png)
执行如下操作:
把
推入栈内,i++。(2b) 栈为空,把
推入栈内,i++。上面的循环操作完毕后,留下的是一个不空的栈。
当栈不为空时进行如下循环:
当前栈顶所对应的是
![h[D_r]](http://zhiqiang.org/bbs/bb-cache/tex_0cc4decbeb0d91ada2cfc15047955c06.png)
先弹出

如果
![h[D_r]*(q_r-p_r+1) > maxS](http://zhiqiang.org/bbs/bb-cache/tex_3803579cad890b841806b625c5313ace.png)
则更新max为
![(h[D_r]*(q_r-p_r+1), p_r, q_r)](http://zhiqiang.org/bbs/bb-cache/tex_e3647433dbfdc2100ddb177459146097.png)
操作完后如果栈不空,设前栈顶为

修改栈顶为

容易知道分摊复杂性是O(1),所以算法的时间复杂度是O(n),空间复杂度是O(n)。
发布于 1 年 之前 # -
把错误稍微改正一下:
三元组
意味着它包含了一个高度为
,从
到
的矩形。
也是一个三元组,表示为
,记
这个变量的值永远为
。
记录了最大的内接矩形。
的定义还是与上面一样,也是记录着最大的内接矩形。维护一个这样一个栈,右边为栈顶:
,
, ... , 
其中
,且
。实际上这个栈代表了当前还未考虑其内接矩形大小的一些相邻矩形。
初始情况栈为:

置
初始为1,当
时进行如下循环(可证每次开始循环时栈不空,此时栈顶元素为
):(1) 若
,则把
进栈,且
;(2) 若
,先弹出
。如果
,
则更新
且
。操作完之后再分3种情况:(2a) 栈不空,设当前栈顶为
,且
:
先修改栈顶为
,执行完操作后
值不变。(2b) 栈不空,设当前栈顶为
,且
:
把
推入栈内,
。(2c) 栈为空,把
推入栈内,
。上面的循环操作完毕后,留下的是一个不空的栈。
当栈不为空时进行如下循环:
当前栈顶所对应的
,先弹出
,如果
,
则更新
且
为
。
操作完后如果栈不空,设前栈顶为
,修改栈顶为
。容易知道分摊复杂性是O
,所以算法的时间复杂度是O
,空间复杂度是O
。
发布于 1 年 之前 # -
效率微调:可以在程序的进行中把一些高度相同的矩形直接合并成一个,不去比较与
的大小,等待下次比较,
因为这样得到的矩形更大且不违反高度的约束。这是一种Lazy Method,很有效。栈中
。循环语句做一些调整:置
初始为1,当
时进行如下循环(可证每次开始循环时栈不空,此时栈顶元素为
):(1) 若
,则把
进栈,且
;(2) 若
,则把栈顶修改为
(2) 若
,先弹出
。如果
,
则更新
且
。操作完之后再分4种情况:(2a) 栈不空,设当前栈顶为
,且
:
修改栈顶为
,执行完操作后
值不变。(2b) 栈不空,设当前栈顶为
,且
:
直接修改栈顶为
,再执行
。(2c) 栈不空,设当前栈顶为
,且
:
先把
推入栈内,再执行
。(2d) 栈为空,把
推入栈内,
。上面的循环操作完毕后,留下的是一个不空的栈。
当栈不为空时进行如下循环:
当前栈顶记为
。先弹出栈顶元素。若
,
则更新
且
。
操作完后如果栈不空,设当前栈顶为
,修改栈顶为
。
发布于 1 年 之前 # -
不错
发布于 1 年 之前 # -
所要的这个最大的矩形可能与直方图的底线只有一个公共点。
楼主考虑到 这个问题了么?
发布于 11 月 之前 #
回复
你必须 登录 后发帖。