最大正方形面积-(前缀和与动态规划力两种解题)

Tips:这主要是自己在秋招过程中的一些学习笔记。GoGoGo!

问题描述:一个m*n的矩阵(m>0,n>0)只有数字0或1组成,找到这个矩阵中只包含1的最大正方形,返回其面积。

解决方案一:前缀和

矩阵的前缀和sum[i][j]理解为左上角坐标[0][0],右下角[i][j]的矩形区域内的数值和。

若要求取左上角坐标[x][y],右下角[i][j]的矩形区域内的数值和tmp,则计算公式如下:

tmp = sum[i][j] - sum[i][j-y] - sum[i-x][j] + sum[x][y];

请看图解:

基于这个想法,求取最大的正方形就可以是,永远以右下角是坐标[i][j],边长从1遍历到min(i,j),去找到最大的填充一的正方形区域。代码如下:

#include <iostream>
#include <vector>

using namespace std;
int main() {
    int m,n;
    cin >> m >> n;

    vector<vector<int>> matrix(m,vector<int>(n));
//为了简化sum的填充
//我们也可以先计算每一行的前缀和,再计算每一行形成的前缀和矩阵的列的前缀和
    vector<vector<int>> sum(m+1,vector<int>(n+1,0));

    for(int i = 0;i < m;++i) {
        for(int j = 0;j < n;++j) {
            cin >> matrix[i][j];
            sum[i+1][j+1] = matrix[i][j] + sum[i][j+1] + sum[i+1][j] - sum[i][j];
        }
    }

    int res = 0;

    for(int i = 0;i <= m;++i) {
        for(int j = 0;j <= n;++j) {
            cout << sum[i][j] << " ";
        }
        cout << endl;
    }

    //想法是从右下角进行计算
    for(int i = m-1;i >0;i--) {
        for(int j = n - 1;j > 0;j--) {
            for(int k = 1;k <= min(i+1,j+1);k++) {
                int temp = sum[i + 1][j + 1] - sum[i + 1 - k][j + 1] - sum[i + 1][j + 1 - k] + sum[i + 1 - k][j + 1 - k];
                if(temp == k*k)
                    res = max(k,res);
            }
        }
    }

    cout << res << endl;

}

输入:

4 4 
1 0 1 0
1 0 1 1
1 1 1 1
0 1 0 1

输出:先打印的是前缀和矩阵,最后一行是边长

0 0 0 0 0
0 1 1 2 2
0 2 2 4 5
0 3 4 7 9
0 3 5 8 11
2

方案二:动态规划

dp矩阵是什么:dp[i][j]以 (i,j) 为右下角,且只包含 1 的正方形的边长最大值。注意一定要是包含右下角,说明matrix[i][j]是0,我们将不更新dp。

如何更新dp:dp的更新取决于[i][j]的[i][j-1],[i-1][j],[i-1][j-1]的值,如果他们中有一个是0,必然dp[i][j] = 1;如果他们之间最小是1,那么dp[i][j] = 2 ....因此,dp[i][j] = min(dp[i][j-1],dp[i-1][j],dp[i-1][j-1]);

代码:

int max_subMatrix(vector<vector<int>>& matrix) {
    int m = matrix.size();
    int n = matrix[0].size();
    //以i,j为右下角的最大正方形边长
    vector<vector<int>> dp(m+1,vector<int>(n+1,0));

    int res = 0;

    for(int i = 0;i < m;++i) {
        for(int j = 0;j < n;++j) {
            if(matrix[i][j] == 1) {
                dp[i+1][j+1] = min(dp[i][j],min(dp[i][j+1],dp[i+1][j])) + 1;
            }
            res = max(res,dp[i+1][j+1]);
        }
    }

    return res;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值