Leetcode 221. Maximal Square 单调队列和dp两种思路求解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/luke2834/article/details/79338681

题意

  • 给定一个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;
    }
};

猜你喜欢

转载自blog.csdn.net/luke2834/article/details/79338681
今日推荐