其他分享
首页 > 其他分享> > 530,动态规划解最大正方形

530,动态规划解最大正方形

作者:互联网

The goal is not always meant to be reached, but to serve as a mark for our aim. 

目标不一定永远都会达到,但可以当我们瞄准的方向。

问题描述

在一个由'0'和'1'组成的二维矩阵内,找到只包含'1'的最大正方形,并返回其面积。

 

示例 1:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

输入:

matrix = 

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

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

 ["1","1","1","1","1"],

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

 

输出:4

 

示例 2:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

输入:matrix = [["0","1"],["1","0"]]

输出:1

示例 3:

输入:matrix = [["0"]]

输出:0

 

提示:

 

动态规划解决

这题让求的是由1围成的最大正方形,最容易想到的一种方式就是暴力求解。解决方式就是如果某个位置是1,就以他为正方形左上角,然后沿着右边和下边找最大的正方形,并且还要保证围成的正方形中所有的数字都是1。

 

这种虽然容易想到但代码不太好写,并且时间复杂度也比较高。下面我们来看另一种实现方式,使用动态规划来解决。

 

定义二维数组dp[m][n],其中dp[i][j]表示的是在矩阵中以坐标(i,j)为右下角的最大正方形边长。如果我们想求dp[i][j],需要判断矩阵中matrix[i][j]的值。

 

如果matrix[i][j]是0就没法构成正方形,所以dp[i][j]=0。

 

如果matrix[i][j]是1,说明他可以构成一个正方形,并且这个正方形的边长最小是1。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

如果左上角的值dp[i-1][j-1]不是0,也就是说他也可以构成正方形,那么以坐标(i,j)为右下角有可能可以构成一个更大的正方形。为啥说是有可能,因为如果我们要确定他能不能构成一个更大的正方形,还要往他的上边和左边找,看下下面的图。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

有可能是下面这种情况,就是左边或者上边的某一个高度小于dp[i-1][j-1]的值,要想构成最大的正方形我们只能取最小的。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

也有可能是下面这种,就是左边和上边的高度都不小于dp[i-1][j-1]的值。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

所以我们可以得出结论,如果(i,j)是1,那么以他为右下角的最大正方形边长是

{dp[i-1][j-1],上边的高度,左边的高度}这3个中最小的+1。

 

这里有个问题就是,如果(i,j)是1,我们有必要往他的上边和左边查找吗,很明显没必要,上边可以用dp[i-1][j]来代表,左边可以用dp[i][j-1]来代表。(注意这里dp[i-1][j]并不是上边为1的高度,dp[i-1][j]只会小,不会大,可以想一下为什么可以代表)

 

所以我们可以找出递推公式

如果坐标(i,j)为0,

则dp[i][j]=0;

 

如果坐标(i,j)为1,

则dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1;

 

为了防止一些不必要的边界条件判断,我把dp数组的长和宽都增加了1,来看下代码

 1public int maximalSquare(char[][] matrix) {
2    //二维矩阵的宽和高
3    int height = matrix.length;
4    int width = matrix[0].length;
5    int[][] dp = new int[height + 1][width + 1];
6    int maxSide = 0;//最大正方形的宽
7    for (int i = 1; i <= height; i++) {
8        for (int j = 1; j <= width; j++) {
9            if (matrix[i - 1][j - 1] == '1') {
10                //递推公式
11                dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i - 1][j - 1], dp[i][j - 1])) + 1;
12                //记录最大的边长
13                maxSide = Math.max(maxSide, dp[i][j]);
14            }
15        }
16    }
17    //返回正方形的面积
18    return maxSide * maxSide;
19}

 

总结

这题代码没什么难度,关键点在于怎么找出动态规划的递推公式,上面画了那么多图就是为了找出这个公式,有了公式代码就很容易写出来了。

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

529,动态规划解最长回文子序列

490,动态规划和双指针解买卖股票的最佳时机

430,剑指 Offer-动态规划求正则表达式匹配

395,动态规划解通配符匹配问题

 

 

截止到目前我已经写了500多道算法题了,为了方便大家阅读,我把部分算法题整理成了pdf文档,目前有900多页,大家可以在公众号中回复关键字“pdf”即可获取下载链接。

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=你点的每个赞,我都认真当成了喜欢

标签:matrix,maxSide,int,正方形,530,动态,dp
来源: https://blog.51cto.com/u_4774266/2902950