【LeetCode】221.最大正方形

57 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情

题目

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

示例 1

img

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

示例 2

img

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

示例 3

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

提示

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 300
  • matrix[i][j] 为 '0' 或 '1'

题解

思路

首先,把矩阵的每一行看作一个二进制数,对于矩阵: 1 0 1 0 0 1 0 1 1 1 两数相与得到 1 0 1 0 0 在这个数字中,连续的 1 就可以看作是正方形的宽,而高度就是 2,因为是 2 个数相与的。要得到正方形,宽和高必须相等,那么就是取宽高中较小的那个作为正方形的边,所以能构成的最大正方形边长为 min(宽,高)=min(1,2)=1。 再来看一个矩阵: 1 0 1 1 1 1 1 1 1 1 相与得到 1 0 1 1 1 连续的 1 有 3 个,所以宽是 3,高仍然是 2,构成的最大正方形边长为 min(宽,高)=min(3,2)=2。

现在我们的任务有 3 个:

  1. 把矩阵每一行看作二进制数的表示形式,进而转成数字,得到一个一维数组;
  2. 用 2 个指针 i,j 分别表示开始行和最后一行,这2行之间的所有行(包括这 2 行)全部相与,看能得到多少个连续最多的 1,亦即求宽度,而高度则等于 j-i+1。枚举所有的(i,j) 组合,并保存结果中的最大值。
  3. 如何求一个数中连续最多的 1?小技巧:每次将这个数和它左移一位后的数相与,直到它变成 0,记录操作次数,这个操作次数就是连续最多的 1。 举个例子: 对于数字 10101010,将这个数和它左移一位后的数相与,操作1次,这个数就变成 0 了,连续最多的 1只有 1 个; 对于数字 10101110,操作 1 次得到 00001100,还需再操作2次才能得到 0,所以连续最多的 1是 3; 相当于每次都错一位相与,所以这个数最多有几个连续的 1,就能错一位相与几次才能得到 0。

代码

class Solution:
    def getWidth(self,num):  #步骤3:求一个数中连续最多的1
        w=0
        while num>0:
            num&=num<<1
            w+=1
        return w
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        nums=[int(''.join(n),base=2) for n in matrix]  #步骤1:每一行当作二进制数
        res,n=0,len(nums)
        for i in range(n):   #步骤2:枚举所有的组合,temp存储相与的结果
            temp=nums[i]
            for j in range(i,n):
                temp&=nums[j]
                w=self.getWidth(temp)
                h=j-i+1
                res=max(res,min(w,h))
        return res*res

结语

业精于勤,荒于嬉;行成于思,毁于随。