2020年5月30日 星期六

LeetCode 84. Largest Rectangle in Histogram [Hard] [C++] 解題筆記

這題給定一個 array,每個值表示一個寬度為1的bar的高度,要我們求這些所組成的最大矩形的面積。

EX:

想法:
          一開始只能很直覺的想到暴力法,就是對於每個 bar  i 分別往左、往右遍歷找到左邊/右邊最後一個不小於他的 bar 的 index (left/right),然後計算 (right - left + 1)*heights[i])  之後就可以得到該 bar 所能組成的最大面積矩形,但這個方法的時間複雜度是 O(n^2),最後一個大測資會吃TLE。

看了一下發現這題大家都用 "Monotonic Stack" 的方式解,可以達到 O(n) time, O(n) space 的複雜度,但我是覺得不大容易自己想到,就紀錄一下。
首先 stack 中要保持遞增順序,因此若 stack 為空或是當前高度 heights[i] 大於等於 stack 的 top 的高度則直接push 進 stack,因為若 heights[i] >= heights[stack.top] 表示前面的 bar 寬度可以延伸到 i 形成更大的矩形,因此還有繼續形成更大矩形的可能所以先不計算,而若 heights[i] < heights[stack.top] 則表示前面的 bar 沒辦法延伸到 i ,因此它所能形成的最大矩形到目前為止已經確定了,可以進行計算,換言之,遇到高度比目前 stack.top 小的 bar 其實是一個開關,遇到這種情況表示 stack.top 的 bar 的右邊界已經找到了就是他自己,所以就可以開始從 stack.top pop stack 中的 bar 出來做計算,一直 pop 到 bar 的高小於 heights[i] 為止 (跟前面一樣,因為高小於當前 bar 的高表示之後還有機會形成更大的矩形),由於 stack 是遞增的且右邊界確定了,因此 stack 每個 bar 可以形成的矩形大小會是本身個高乘上與邊界的距離(寬),
i.e. heights[stack.top] * (i - stack.top - 1)。


完整程式碼:

解法一 ( brute-force):

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int max_area = 0;
        
        for (int i = 0; i < heights.size(); i++) {
            int left = i;
            int right = i;
            for (int j = i - 1; j >= 0; j--) {
                if (heights[j] >= heights[i]) {
                    left = j;
                }
                else {
                    break; 
                }
            }
            for (int j = i + 1; j < heights.size(); j++) {
                if (heights[j] >= heights[i]) {
                    right = j;
                }
                else {
                    break;
                }
            }
            max_area = max(max_area, (right - left + 1)*heights[i]);
        }
        return max_area;
    }
};

解法二 (Monotonic stack):

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        vector<int> stack;
           // avoid heights is in increasing order
        heights.push_back(0);
        int i = 0;
        int res = 0;
        while ( i < heights.size()) {
            if (stack.empty() || heights[i] >= heights[stack.back()]) {
                stack.push_back(i++);
            }
            else {
                int h = heights[stack.back()];
                stack.pop_back();
                int w = (stack.empty())? i : i - stack.back() - 1;
                res = max(res, h*w);
            }
        }
        return res;
    }
};



沒有留言:

張貼留言