算法学习记录(八十九)

70 阅读2分钟

221. 最大正方形

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

image.png

解:

写了暴力解的优化版本,写完之后看了题解才发现还有DP解。。。

暴力解: 遍历二维数组,以每个为1的元素作为左上顶点,从1开始依次扩充作为正方形的边长,并且正方形内每个元素判断是否为1。也就是要遍历4层。

优化版本:

  1. 预处理生成两个二维数组grid,grid2。
  2. 其含义分别为:grid[i][j]是第i行第j个元素,从左往右数连续几个1。grid2[i][j]是第i行第j个元素从上往下数连续几个1。
  3. 有了预处理数组之后,在暴力解选定左上顶点之后,在预处理数组中找到这个顶点往下和往右连续几个1。其中较小的值是正方形边长的第一个瓶颈。
  4. 假设matrix[i][j]这个元素往右连续3个1,往下连续4个1。那么边长瓶颈就是3,所以从这个顶点开始往右遍历3格,查询每个点往下能有几个1。
  5. 查询的过程中,记录其中每个点往下连续几个1的最小值,这是第二个瓶颈。
  6. 假设第二个点往下只有连续1个1,那么不需要再往后遍历了,后面不可能形成正方形。
  7. 没有遇到瓶颈的时候就计算一次面积,从左到右遍历完之后计算一次全局最大面积
const maximalSquare = function(matrix) {
    const y = matrix.length
    const x = matrix[0].length
    let maxArea = 0
    // 生成预处理数组
    const { grid, grid2 } = preHandle()
    // 遍历每个元素当做左上顶点
    for (let i = 0; i < y; i++) {
        for (let j = 0; j < x; j++) {
            // 看这个顶点的第一个瓶颈,即顶点可能以该长度作为边长
            const len = Math.min(grid[i][j], grid2[i][j])
            if (matrix[i][j] !== '1' || !len) continue
            const bigOne = grid[i][j] > grid2[i][j] ? grid : grid2
            const smallOne = bigOne === grid ? grid2 : grid
            // 当前面积
            let tempArea = 0
            // 第二个瓶颈,即边长上的元素最少连续几个1
            let bottleneck = Infinity
            // 依次查看是否满足正方形条件
            for (let k = 0; k < len; k++) {
                // 如果瓶颈是x轴方向,那么就依次查看沿着x轴方向上每个元素连续几个1
                const targetLen = smallOne === grid ? grid2[i][j + k] : grid[i + k][j]
                // 如果遇到第二个瓶颈,往后不再能形成正方形跳出循环
                if (k + 1 > bottleneck) break
                // 设置瓶颈
                bottleneck = Math.min(targetLen, bottleneck)
                // 如果没遇到瓶颈,那么k+1是可以作为正方形边长的,计算一次长度
                if (targetLen >= k + 1) {
                    tempArea = (k + 1) ** 2
                }
            }
            // 设置全局最大面积
            maxArea = Math.max(tempArea, maxArea)
        }
    }
    return maxArea
    function preHandle () {
        const grid = []
        const grid2 = []
        for (let i = 0; i < y; i++) {
            grid[i] = []
            grid2[i] = []
        }
        for (let i = 0; i < y; i++) {
            grid[i][x - 1] = matrix[i][x - 1] === '1' ? 1 : 0
        }
        for (let i = 0; i < x; i++) {
            grid2[y - 1][i] = matrix[y - 1][i] === '1' ? 1: 0
        }
        for (let i = y - 1; i >= 0; i--) {
            for (let j = x - 2; j >= 0; j--) {
                grid[i][j] = matrix[i][j] === '1' ? grid[i][j + 1] + 1 : 0
            }
        }
        for (let i = y - 2; i >= 0; i--) {
            for (let j = x - 1; j >= 0; j--) {
                grid2[i][j] = matrix[i][j] === '1' ? grid2[i + 1][j] + 1 : 0
            }
        }
        return { grid, grid2 }
    }
};