[leetcode] 221. Maximal Square && 85. Maximal Rectangle

Maximal Square

Given a 2D binary matrix filled with 0’s and 1’s, find the largest square containing only 1’s and return its area.
Example:

Input:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Output: 4

解法

動態規劃,找到每一個位置的可以達到的最大的正方形的邊長。

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        if(matrix.empty() || matrix[0].empty())
            return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<vector<int> > dp(m, vector<int> (n, 0));
        int res = 0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(i == 0 || j == 0)
                    dp[i][j] = matrix[i][j] == '1' ? 1:0;
                else{
                    if(matrix[i][j] == '1')
                        dp[i][j] = min(dp[i][j-1],min(dp[i-1][j],dp[i-1][j-1])) + 1;
                    else
                        dp[i][j] = 0;
                }
                res = max(res, dp[i][j]);
            }
        }
        return res*res;
    }
};

Maximal Rectangle

Given a 2D binary matrix filled with 0’s and 1’s, find the largest rectangle containing only 1’s and return its area.
Example:

Input:
[
[“1”,“0”,“1”,“0”,“0”],
[“1”,“0”,“1”,“1”,“1”],
[“1”,“1”,“1”,“1”,“1”],
[“1”,“0”,“0”,“1”,“0”]
]
Output: 6

直方圖中最大的面積

可以把這個問題變成求直方圖中最大的矩形面積;
對矩陣的每一行加上這行之前的所有行構成一個直方圖heights,如果當前值爲1,則heights[j]++,否則爲0
對每一個直方圖進行求最大面積值,最後得到的所有直方圖的最大面積就是結果。

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if(matrix.empty() || matrix[0].empty())
            return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<int> heights(n, 0);
        int res = 0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(matrix[i][j] == '1')
                    heights[j] ++;
                else
                    heights[j]= 0;  
            }
            res = max(res,LargeRecinHisto(heights));
        }
        return res;
    }
    
    int LargeRecinHisto(vector<int> heights){
        stack<int> s;
        heights.push_back(0);
        int max_value = 0;
        for(int i=0;i<heights.size();i++){
            if(s.empty() || heights[i] >= heights[s.top()])
                s.push(i);
            else{
                while(!s.empty() && heights[i] < heights[s.top()]){
                    int cur = s.top(); 
                    s.pop();
                    max_value = max(max_value, heights[cur]*(s.empty() ? i : i-s.top()-1));
                }
                s.push(i);
            }   
        }
        return max_value;
    }
};

一個函數解決

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if(matrix.empty() || matrix[0].empty())
            return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<int> heights(n+1, 0);
        int res = 0;
        for(int i=0;i<m;i++){
            stack<int> s;
            for(int j=0;j<n+1;j++){
                if(j<n)
                    heights[j] = matrix[i][j] == '1' ? heights[j]+1:0;
                while(!s.empty() && heights[j] <= heights[s.top()]){
                    int cur = s.top(); 
                    s.pop();
                    res = max(res, heights[cur]*(s.empty() ? j : j-s.top()-1));
                }
                s.push(j);
            }
        }
        return res;
    }
};

解法2

構造一個heights數組和解法1相同,然後再構造一個left和right數組
left數組表示:如果當前值matrix[i][j]==1,left[j]爲與其相連都爲1的左邊界位置,否則爲0;
right數組表示:如果當前值matrix[i][j]==1,right[j]爲與其相連都爲1的右邊界位置+1,否則爲n;
對於任意一個位置的[i][j],面積表示爲(right[j]-left[j])*heights[j]。
舉個栗子:

[
[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]
]

第0行:

h: 1 1 0 0 1
l: 0 0 0 0 4
r: 2 2 5 5 5

第1行:

h: 0 2 0 0 2
l: 0 1 0 0 4
r: 5 2 5 5 5

第2行:

h: 0 0 1 1 3
l: 0 0 2 2 4
r: 5 5 5 5 5

第3行:

h: 0 0 2 2 4
l: 0 0 2 2 4
r: 5 5 5 5 5

第4行:

h: 0 0 0 0 5
l: 0 0 0 0 4
r: 5 5 5 5 5

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if(matrix.empty() || matrix[0].empty())
            return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<int> heights(n, 0), left(n, 0), right(n, n);
        int res = 0;
        for(int i=0;i<m;i++){
            int cur_left = 0, cur_right = n;
            for(int j=0;j<n;j++){
                if(matrix[i][j] == '1'){
                    heights[j]++;
                    left[j] = max(left[j], cur_left);
                }
                else{
                    heights[j] = 0;
                    left[j] = 0;
                    cur_left = j+1;
                }
            }
            
            for(int j=n-1;j>=0;j--){
                if(matrix[i][j] == '1')
                    right[j] = min(right[j], cur_right);
                else{
                    right[j] = n;
                    cur_right = j;
                }
                res = max(res, (right[j] - left[j]) * heights[j]);
            }
        }
        return res;
    }
};

解法3

先統計每一行的連續1的個數,使用一個數組 h_max, 其中 h_max[i][j] 表示第i行,第j個位置水平方向連續1的個數,若 matrix[i][j] 爲0,那對應的 h_max[i][j] 也一定爲0;
再次遍歷每個位置,首先每個位置的 h_max 值都先用來更新結果 res,因爲高度爲1也可以看作是矩形,然後我們向上方遍歷,上方 (i, j-1) 位置也會有 h_max 值,但是用二者之間的較小值才能構成矩形,用新的矩形面積來更新結果 res,這樣一直向上遍歷,直到遇到0,或者是越界的時候停止,這樣就可以找出所有的矩形了。

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if(matrix.empty() || matrix[0].empty())
            return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<vector<int> > h_max(m, vector<int> (n,0));
        int res = 0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if (matrix[i][j] == '0') continue;
                if (j > 0) h_max[i][j] = h_max[i][j - 1] + 1;
                else h_max[i][0] = 1;
            }
        }
        for(int i=0;i<m;i++){
            for (int j = 0; j < n; ++j) {
                if (h_max[i][j] == 0) continue;
                int mn = h_max[i][j];
                res = max(res, mn);
                for (int k = i - 1; k >= 0 && h_max[k][j] != 0; --k) {
                    mn = min(mn, h_max[k][j]);
                    res = max(res, mn * (i - k + 1));
                }
            }
        }
        return res;
    }
};

參考

https://www.cnblogs.com/grandyang/p/4322667.html

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