Leetcode個題解85

LEETCODE專題


85. Maximal Rectangle

題目要求:
這裏寫圖片描述

在一個矩陣中找到所有全爲’1’的方形區域的面積並求出最大值。


問題:

  1. 如何得出這些區域?
  2. 如何求出這些區域的面積?

分析:

  1. 如果大家都被筆者帶入去思考第一個問題的話,那麼恭喜你,中了本題最大的坑當中了(@_@)。當然對於一些高手來說,這樣做也是沒有問題的。但是筆者要在這裏介紹一下另一種方法,這來自於Leetcode的discussion板塊的貢獻者morrischen2008大神。
    這裏要先糾正一下剛剛被筆者帶入坑的各位朋友——其實我們根本不用費力去求這些區域,我們只需要記住當前的“最左邊界值”、“最右邊界值”以及高度即可。這裏有關邊界值的描述加了引號,是因爲這不一定是最左或者最右的,舉個例子:

    [0, 0, 1, 1, 1
    0, 0, 1, 1, 1
    0, 1, 1, 1, 1]
    

    我們從0開始計數。這個時候點(2, 2)的最左邊界值就應該爲2而非1,如果爲1的話高度就會減少。而我們針對這種情況可以採用點[2, 1]最右邊界值來參與計算包含該點的矩形,結果爲4,即使它不是最大的面積。

有了這一個思路之後,我們就可以來設計這個算法啦。

  1. 最左邊界值的選取。我們可以讓每一行每個元素都有這個屬性,且這個屬性可以繼承自上一行的元素的最左邊界值。在計算該行最左邊界值時,再加入一個參數curLeft,也就是當前未出現0的最左邊界值(這裏的最左邊界值則是真的最左邊界值,爲了區分,我們用left2表示該值,用left1表示要計算的最左邊界值,最右邊界值也採用這種方法加以區分),參與計算。在left1和left2之間選取一個最大值作爲該點的最左邊界值,以保留上一行的高度。
    計算順序:從左到右。
  2. 最右邊界值的選取。除了加入的參數爲curRight,且計算的時候選取的是right1與right2的最大值之外,其他的與最左邊界值選取過程一致。
    計算順序:從右到左。
  3. 高度值height選取。高度是一個積累過程,如果有連續的’1’則累加,遇到’0’則清零。
  4. 面積的計算。有了以上的基礎,我們就可以用簡單的公式來計算矩形的面積啦。公式就是(right - left) * height。
  5. 去最大的面積,也就是再將每個面積都比較一下。方法有很多,具體就不再贅述了。

下面直接上代碼:

class Solution {
public:
    int max(int a, int b) {
        return a > b ? a : b;
    }

    int min(int a, int b) {
        return a < b ? a : b;
    }

    int maximalRectangle(vector<vector<char>>& matrix) {
        /*
         * every item saves its leftest bound, its rightest bound and its height
         * 1. whenever its char is '0', the cumulative height will be 0
         * 2. the rightest bound of each factor is initialed to be the largest value
         *    and calculated from right to left, with the value of minimum of
         *    curRight and the rightest bound of the last row.
         * 3. the leftest bound of each factor is initialed to be the smallest value
         *    and calculated from left to right, with the value of maximum of
         *    curLeft and the leftest bound of the last row.
         */

        int row = matrix.size();
        if (row == 0) return 0;
        int col = matrix[0].size();
        if (col == 0) return 0;
        int r, c;

        vector<int> left(col, 0);
        vector<int> right(col, col);
        vector<int> height(col, 0);

        int maxArea = 0;

        for (r = 0; r < row; r++) {
            int curLeft = 0;
            int curRight = col;
            for (c = 0; c < col; c++) {
                if (matrix[r][c] == '1') {
                    left[c] = max(left[c], curLeft);
                    height[c]++;
                } else {
                    left[c] = 0;
                    curLeft = c + 1;
                    height[c] = 0;
                }
            }
            for (c = col - 1; c >= 0; c--) {
                if (matrix[r][c] == '1') {
                    right[c] = min(right[c], curRight);
                } else {
                    right[c] = col;
                    curRight = c;
                }
                maxArea = max(maxArea, (right[c] - left[c]) * height[c]);
            }
        }

        return maxArea;
    }
};

時間複雜度:O(n)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章