直方圖的最大矩形面積的棧優化思想

本來並無重視這個技巧,可是後來回過頭再來作幾道關於DP的題目,意外地發現這個作法能夠將O(n^2)的複雜度優化至O(n)!因此打算將這類題目作一個總結吧。bash


直方圖最大矩形覆蓋

Description

Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.優化

For example, given height = [2,1,5,6,2,3].ui

heights

The largest rectangle area is 10 unit.spa

area

Thinking

基本思想:用棧維護一個遞增子序列3d

爲了方便記錄矩形的寬度,咱們在棧中存放的是矩形的下標。code

咱們用 i 遍歷全部的矩形,當棧尾元素 j 對應的矩形高度大於或等於當前遍歷到的矩形時(出現了局部非遞增),能夠保證:前面出現的上升序列中可能存在最大面積。以下圖:cdn

這樣當遇到局部遞減時,依次取出棧尾,若是 s 未空面積 area = height[cur] * (i-s.top()-1) 就是棧尾元素對應的高度乘以跨度,若是此時s已空, area = height[cur] * iblog

最後須要注意,爲防止全是單調上升的狀況致使 s 沒法清空,能夠增設一個高度爲 0 的矩形。ip

Code

class Solution {
public:
    /** * @param height: A list of integer * @return: The area of largest rectangle in the histogram */
    int largestRectangleArea(vector<int> &height) {
        int result = 0;
        height.push_back(0);
        stack<int> s;
        for (int i = 0; i < height.size(); ++i) {
            while (!s.empty() && height[s.top()] >= height[i]) {
                int cur = s.top(), area;
                s.pop();
                if (s.empty()) area = height[cur] * i;
                else area = height[cur] * (i-s.top()-1);
                result = max(result, area);
            }
            s.push(i);
        }
        return result;
    }
};

複製代碼

最大矩形

Description

給你一個二維矩陣,權值爲False和True,找到一個最大的矩形,使得裏面的值所有爲True,輸出它的面積get

好比,給你一個矩陣以下

1  1  0  0  1
0  1  0  0  1
0  0  1  1  1
0  0  1  1  1
0  0  0  0  1
複製代碼

答案是6

Thinking

先用相似前綴和的作法先預處理原矩形,在縱向上來看,全部的1能夠類加成高度

1  1  0  0  1
0  2  0  0  2
0  0  1  1  3
0  0  2  2  4
0  0  0  0  5
複製代碼

因而能夠在O(1)的時間裏得到當前行的矩形高度,而後用相似「直方圖最大矩形面積」的作法求出每一行段的最大面積,就能夠找出最大值。

綜上,時間複雜度O(n^2)

Code

class Solution {
private:
    int getLayerMax(vector<int> &height) {
        int _max = 0, size = height.size();
        stack<int> s;
        height.push_back(0);
        for (int i = 0; i < height.size(); ++i) {
            while (!s.empty() && height[i] <= height[s.top()]) {
                int cur = s.top();
                s.pop();
                if (s.empty()) _max = max(_max, height[cur]*i);
                else _max = max(_max, height[cur]*(i-s.top()-1));
            }
            s.push(i);
        }
        return _max;
    }
public:
    int maximalRectangle(vector<vector<bool> > &matrix) {
        if (matrix.empty() || matrix[0].empty()) return 0;
        int m = matrix.size(), n = matrix[0].size(), _max = 0;

        vector<vector<int> > prefix(m, vector<int>(n, 0));

        for (int j = 0; j < n; ++j)
            for (int i = 0; i < m; ++i)
                if (!matrix[i][j]) prefix[i][j] = 0;
                else prefix[i][j] = (i==0) ? 1 : prefix[i-1][j] + 1;

        for (int i = 0; i < m; ++i)
        	_max = max(_max, getLayerMax(prefix[i]));

        return _max;
    }
};

複製代碼
相關文章
相關標籤/搜索