题目
在一个由 '0' 和 '1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。 示例 1:
输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:4
示例 2:
输入:matrix = [["0","1"],["1","0"]]
输出:1
示例 3:
输入:matrix = [["0"]]
输出:0
动态规划四步走
1. 定义状态
2. 初始状态
3. 状态转移方程
4. 从dp[]中获取结果
具体到题目
定义状态
定义dp[][],其中dp[i][j]表示到matrix[i][j]的最大正方形的边长
初始状态
dp[0][0] = matrix[0][0]; 行和列的初始化都比较简单,碰到1之后,后面的都是1
状态转移方程
对于dp[i][j],需要判断左边dp[i][j-1]和上面dp[i-1][j]综合得到。 如果matrix[i][j] === 0,dp[i][j] 为dp[i][j-1]和dp[i-1][j]的较大值。 如果matrix[i][j] === 1,dp[i][j] 可能比dp[i][j-1]和dp[i-1][j]的最大值还大1,并且同时需要小于i和j,假设p = Math.max(dp[i][j-1],dp[i-1][j])+1 (p <= i && p <= j)只需要遍历是matrix[i-p][j-p]到matrix[i][j]是否全为1既可,若满足,则dp[i][j]=p,否则,p[i][j]为dp[i][j-1]和dp[i-1][j]的较大值。
if matrix[i][j] === 0
dp[i][j] = Math.max(dp[i][j-1],dp[i-1][j])
else
p = Math.max(dp[i][j-1],dp[i-1][j])+1 (p <= i && p <= j)
if matrix[i-p][j-p]到matrix[i][j]是否全为1
matrix[i][j] = p
else
dp[i][j] = Math.max(dp[i][j-1],dp[i-1][j])
从dp[]中获取结果
dp[n-1][m-1]就是最大正方形的边长,求平方就是最后的结果
完整代码
// @lc code=start
/**
* @param {character[][]} matrix
* @return {number}
*/
var maximalSquare = function (matrix) {
const n = matrix.length;
if (!n) {
return 0;
}
const m = matrix[0].length;
const dp = new Array(n).fill(0).map(() => new Array(m));
dp[0][0] = matrix[0][0];
for (let i = 1; i < m; i++) {
dp[0][i] = Math.max(matrix[0][i], dp[0][i - 1]);
}
for (let i = 1; i < n; i++) {
dp[i][0] = Math.max(matrix[i][0], dp[i - 1][0]);
}
for (let i = 1; i < n; i++) {
for (let j = 1; j < m; j++) {
if (matrix[i][j] === '0') {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
} else {
const max = Math.max(dp[i - 1][j], dp[i][j - 1]);
const bigger = max + 1;
if (bigger > Math.min(i, j) + 1) {
dp[i][j] = max;
} else {
dp[i][j] = helpFn(matrix, i, j, bigger) ? bigger : max;
}
}
}
}
console.log(dp);
const res = dp[n - 1][m - 1];
console.log(res);
return Math.pow(res, 2);
};
const helpFn = (matrix, i, j, bigger) => {
for (let p = i; p > i - bigger; p--) {
for (let q = j; q > j - bigger; q--) {
if (matrix[p][q] === '0') {
return false;
}
}
}
return true;
};
官方做法比较
本题的官方做法是定义的dp[i][j]表示的是以matrix[i][j]为右下角的最大正方形边长,并且得出的状态转移方程是
dp(i,j)= Math.min(dp(i−1,j),dp(i−1,j−1),dp(i,j−1))+1
最后的结果需要从dp数组中找最大值
总结
最大的感受是,dp数组承载的并不一定是最后的结果,这个思想需要时刻注意一下。