这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战
这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。
166. 最大正方形 (maximal-square)
标签
- 动态规划
- 中等
题目
在一个由 '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
基本思路
其实大部分
求最值
问题,动态规划的解法都适用。
从动态规划这篇我们了解到动态规划的基本步骤是下面三步:
- 寻找最优子结构(状态表示)
- 归纳状态转移方程(状态计算)
- 边界初始化
我们还是根据之前的基本步骤来
- 状态表示:
目标是正方形面积,可以转化成找出最大边长来代替
而我们要求的是整个矩阵的最大边长的话,就以 [i, j] 做为右下角坐标,那么 可以设置
dp[i][j]
为 右下角坐标
, 能形成的最大正方形边长
。这样假设矩阵是 m * n, dp[m][n]
为右下角,得出答案后再平方就是面积。
- 状态转移方程:
- 边界初始化:
首先前提条件要是 matrix[i][j] === '1'
, 边界上 i === 0 或者 j === 0
的情况下 , dp[i][j] = 1
这很好理解,贴边上的最大也就是 1 为边长。(i ,j) 是右下角注意。
右下角为 坐标[i][j],它要向左上方去看历史情况
如果(i, j)
的值是 1,则 dp(i,j) 的值由其上方、左方和左上方
的三个相邻位置的 dp 值决定。具体而言,当前位置的元素值等于三个相邻位置的元素中的最小值加 1
。因为你要都是 1
的正方形,根据木桶原理,取最短的都是 1 的情况才行。
代码实现
const maximalSquare = (matrix) => {
let maxLen = 0, rows = matrix.length, cols = matrix[0].length
// 建立 dp
let dp = new Array(rows).fill(0).map(() => new Array(cols).fill(0))
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
// 当角上是 1 计算才有意义
if (matrix[i][j] === '1') {
// 角贴边,肯定最大只能是1了, 这是边界条件
if (i === 0 || j === 0) {
dp[i][j] = 1
} else {
// 木桶原理,取最短的一边为边长
dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1
}
// 每轮更新最大值
maxLen = Math.max(maxLen, dp[i][j])
}
}
}
return maxLen * maxLen;
};
let matrix = [
["1","0","1","0","0"],
["1","0","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]]
console.log(maximalSquare(matrix))
注释应该比较清晰了
另外向大家着重推荐下这个系列的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列
今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 点击此处交个朋友
Or 搜索我的微信号infinity_9368
,可以聊天说地
加我暗号 "天王盖地虎" 下一句的英文
,验证消息请发给我
presious tower shock the rever monster
,我看到就通过,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧