1. 程式人生 > >LeetCode:84. Largest Rectangle in Histogram

LeetCode:84. 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.

題目大意就是給出一個柱狀圖的高度的陣列,求出其中能畫出的最大矩形的面積。

1.方法一
一個比較簡單暴力,容易理解的方法:對於每一個方柱,分別向左向右遍歷,到達第一個小於該方柱高度的方柱停止,此時畫出了一個以該方柱為最小高度的最大矩形,可以計算出面積:

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        if (heights.empty())
            return 0;
        int max = 0;
        for (int i = 0; i < heights.size(); ++i) {
            if (heights[i] <= max/heights.size()) continue;//如果該方柱高度過低,那也沒有計算的必要了,略過
            int temp = helper(heights, i);
            if (temp > max)
                max = temp;
        }
        return max;       
    }
private:
    int helper(const vector<int>& heights, int i) {
        if (heights[i] == 0) return 0;
        int l = i, r = i;
        while(l-1 >= 0 && heights[l-1] >= heights[i]) --l;
        while(r+1 < heights.size() && heights[r+1] >= heights[i]) ++r;
        return heights[i] * (r-l+1);
    }
};

2.方法二
解法來源:https://www.geeksforgeeks.org/largest-rectangle-under-histogram/
比較難以理解,但是該方法時間複雜度為O(N),值得思考。
方法是這樣的:還是要找出以每個方柱為最低高度的最大矩形,關鍵就是找出左邊第一個小於該高度的和右邊第一個小於該高度的。維持一個stack,遍歷輸入的陣列。如果當前遍歷的該方柱高度大於等於棧頂的方柱高度,那麼就將其壓入棧;如果當前遍歷的該方柱高度小於棧頂的方柱高度,就一直將棧頂元素彈出,直到該方柱高度大於等於棧頂的方柱高度。對於每個彈出的方柱,計算以它為最低高度的最大矩形的面積,計算的方法:彈出後當前棧頂的方柱是左邊第一個小於該高度的方柱,當前遍歷的方柱是右邊第一個小於該高度的方柱。
這是從左往右遍歷的。實際程式設計中,為了方便,往往在右邊放一個高度為0的方柱作為哨兵,然後從右往左遍歷。
光看文字描述比較難以理解,需要自己在草稿紙上舉一個例子,將整個過程模擬一遍,好好體會一下。
下面是我的程式碼:

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        if (heights.empty())
            return 0;
        int max = 0;
        heights.push_back(0);//作為哨兵
        int N = heights.size();
        stack<int> si;
        si.push(N-1);
        for (int i = N-2; i >= 0; --i) {
            if (heights[i] >= heights[si.top()]) {
                si.push(i);
                continue;
            }
            while (heights[si.top()] > heights[i]) {
                int t = si.top();
                si.pop();
                int s = heights[t] * (si.top()-i-1);
                if (s > max)
                    max = s;
            }
            si.push(i);
        }
        while (si.size() > 1) {//遍歷結束後,將棧裡面殘留的元素彈出
            int t = si.top();
            si.pop();
            int s = heights[t] * (si.top()-(-1)-1);
            if (s > max)
                max = s;
        }
        return max;
    }
};