1. 程式人生 > >Leetcode 221. Maximal Square 單調佇列和dp兩種思路求解

Leetcode 221. Maximal Square 單調佇列和dp兩種思路求解

題意

  • 給定一個0,1矩陣,希望找到矩陣中的一個面積最大的聯通正方形區域,這個區域中全是1

思路

  • 基本思路:找面積最大的,其實就是找最長的邊長,我們的思路都是以這個為出發點的

dp思路

  • 整體來看,就是一個二維dp,是這類矩陣問題的一個常用狀態設定方法: d p (
    i , j )
    的含義是以 ( i , j )
    為右下角的最大正方形邊長
  • 然後遞推方程,我們一定是看 d p ( i 1 ,
    j )
    d p ( i , j 1 ) 以及 d p ( i 1 , j 1 )
  • 通過觀察矩陣形狀,我們不難發現當 d p ( i , j 1 ) d p ( i 1 , j ) 時,小的那個正方形決定了 ( i , j ) 為右下角這個正方形的邊長,這時 d p ( i , j ) = min ( d p ( i , j 1 ) , d p ( i 1 , j ) ) + 1
  • 而當 d p ( i , j 1 ) = d p ( i 1 , j ) 時,左上角的位置是否為0決定了當前正方形的邊長,這時可以用個小trick,不用真去看左上角為 0 還是 1 ,可以通過 d p ( i 1 , j 1 ) 去判斷一下(這個小trick意義不大,就是遞推形式上更像dp,2333),即
    d p ( i , j ) = d p ( i , j 1 ) + 1 , i f d p ( i 1 , j 1 ) d p ( i , j 1 ) d p ( i , j ) = d p ( i , j 1 ) , O t h e r w i s e

單調佇列思路

  • 這個問題我們可以把行列分開來看
  • 我們先對每一行單獨來看,計算第 i 個元素前有多少個連續的 1 ,存下來
  • 再對每一列單獨去看,我們的任務就變成在一個一維陣列中,找到最長連續子段,這個子段上元素的最小值要大於等於子段的長度
  • 這個很類似於滑動視窗最大值之類的問題,比較容易想到用一個單調佇列就可以了,具體操作可以參考實現

實現

  • 單調佇列實現
class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        if (matrix.size() == 0)
            return 0;
        int n = matrix.size(), m = matrix[0].size();
        vector<vector<int>> a(n, vector<int>(m, 0));
        for (int i = 0; i < n; i++){
            for (int j = 0; j < m; j++){
                if (matrix[i][j] == '0'){
                    a[i][j] = 0;
                }
                else{
                    if (j == 0){
                        a[i][j] = 1;
                    }
                    else{
                        a[i][j] += a[i][j - 1] + 1;
                    }
                }
            }
        }
        int ans = 0;
        for (int j = 0; j < m; j++){
            deque<pair<int, int> > q;
            int len = 1;
            for (int i = 0; i < n; i++){
                while (q.size() && q.back().first > a[i][j]){
                    q.pop_back();
                }
                q.push_back(make_pair(a[i][j], i));
                if (q.front().first < len){
                    len = i - q.front().second + 1;
                    q.pop_front();
                }
                else {
                    ans = max(ans, len);
                    len++;
                }
            }
        }
        return ans * ans;
    }
};
  • dp實現
class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        if (matrix.size() == 0)
            return 0;
        int n = matrix.size(), m = matrix[0].size();
        vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
        int ans = 0;
        for (int i = 1; i <= n; i++){
            for (int j = 1; j <= m; j++){
                if (matrix[i-1][j-1] == '0'){
                    continue;
                }
                if (dp[i-1][j] == dp[i][j-1]){
                    dp[i][j] = dp[i-1][j];
                    if (dp[i-1][j-1] >= dp[i-1][j]){
                        dp[i][j]++;
                    }
                }
                else{
                    dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + 1;
                }
                ans = max(ans, dp[i][j]);
            }
        }
        return ans * ans;
    }
};