1. 程式人生 > >Largest Rectangle in Histogram 直方圖中最大的矩形

Largest Rectangle in Histogram 直方圖中最大的矩形

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.

在這裡插入圖片描述

Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3]. 在這裡插入圖片描述

The largest rectangle is shown in the shaded area, which has area = 10 unit.

For example, Given height = [2,1,5,6,2,3], return 10.

這道題讓求直方圖中最大的矩形,一種很好的優化方法,就是遍歷陣列,每找到一個區域性峰值,然後向前遍歷所有的值,算出共同的矩形面積,每次對比保留最大值,程式碼如下:

解法一:

// Pruning optimize
class Solution {
public:
    int largestRectangleArea(vector<int> &height) {
        int res = 0;
        for (int i = 0; i < height.size(); ++i) {
            if (i + 1 < height.size() && height[i] <= height[i + 1]) {
                continue;
            }
            int minH = height[i];
            for (int j = i; j >= 0; --j) {
                minH = min(minH, height[j]);
                int area = minH * (i - j + 1);
                res = max(res, area);
            }
        }
        return res;
    }
};

後來又在網上發現一種比較流行的解法,是利用棧來解,其核心思想跟上面那種剪枝的方法有異曲同工之妙,這裡維護一個棧,用來儲存遞增序列,相當於上面那種方法的找區域性峰值。我們可以看到,直方圖矩形面積要最大的話,需要儘可能的使得連續的矩形多,並且最低一塊的高度要高。有點像木桶原理一樣,總是最低的那塊板子決定桶的裝水量。那麼既然需要用單調棧來做,首先要考慮到底用遞增棧,還是用遞減棧來做。我們想啊,遞增棧是維護遞增的順序,當遇到小於棧頂元素的數就開始處理,而遞減棧正好相反,維護遞減的順序,當遇到大於棧頂元素的數開始處理。那麼根據這道題的特點,我們需要按從高板子到低板子的順序處理,先處理最高的板子,寬度為1,然後再處理旁邊矮一些的板子,此時長度為2,因為之前的高板子可組成矮板子的矩形 ,因此我們需要一個遞增棧,當遇到大的數字直接進棧,而當遇到小於棧頂元素的數字時,就要取出棧頂元素進行處理了,那取出的順序就是從高板子到矮板子了,於是乎遇到的較小的數字只是一個觸發,表示現在需要開始計算矩形面積了,為了使得最後一塊板子也被處理,這裡用了個小trick,在高度陣列最後面加上一個0,這樣原先的最後一個板子也可以被處理了。由於棧頂元素是矩形的高度,那麼關鍵就是求出來寬度,那麼跟之前那道Trapping Rain Water一樣,單調棧中不能放高度,而是需要放座標。由於我們先取出棧中最高的板子,那麼就可以先算出長度為1的矩形面積了,然後再取下一個板子,此時根據矮板子的高度算長度為2的矩形面積,以此類推,知道數字大於棧頂元素為止,再次進棧,巧妙的一比!程式碼如下:

class Solution {
public:
    int largestRectangleArea(vector<int> &height) {
        int res = 0;
        stack<int> st;
        height.push_back(0);
        for (int i = 0; i < height.size(); ++i) {
            if (st.empty() || height[st.top()] < height[i]) {
                st.push(i);
            } else {
                int cur = st.top(); st.pop();
                res = max(res, height[cur] * (st.empty() ? i : (i - st.top() - 1)));
                --i;
            }     
        }
        return res;
    }
};