221.最大正方形

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

示例:

输入: 

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

输出: 4

思路:给出一个矩形,让去求解其只包含1的最大正方形,并返回面积。所以其实也就是求围成正方形的最大边长。这个题我是没有思路,以前逃避动态规划,今天不得不面对动态规划。那么这个题有两个解法,一个是二进制解法;另一个是动态规划算法。二进制解法的思路就是枚举所有行的组合,主要有三个步骤,第一:先将原来的二维矩阵转换成二进制的一维矩阵。第二:将第一行与其余行进行与操作,看看有多少个连续的1,这个也就是宽,然后计算不同行的高,长方形的边长是求长和宽的最小就行了。然后循环遍历,比较出来最大值即可。这有两个问题:1、进行与操作(0001&1101=0001)只有一个连续的1,所以宽就是1。2、如何计算有几个连续的1呢?让它与它左移后进行与操作,直至它为0.记录移动的次数,就是几个连续的1。举个例子:1111.它有4个连续的1。则它需要左移4次就全为0了。1011;左移与操作还有1个1,再次进行左移与操作就正剩下0了。所以进行了两次操作,那么就有两个连续的1。接下来是动态规划的算法。dp[i,j]表示以[i,j]坐标为右下角,能围成的最大面积,如果左下角是1,那么上、左、坐上都必须为非0.否则正方形就围不了。如果满足dp[i-1][j-1],dp[i-1][j],dp[i][j-1]都是大于0.那么更新dp[i,j]的值,应该是前三个的最小值加上1.这个就是边长,然后不断的更新,取最大的dp[i,j]。然后进行平方就求解出来了。

1、二进制法

class Solution:
    #计算有几个连续的1
    def getWidth(self,num):
        count = 0
        while num>0:
            num&=num<<1
            count+=1
        return count
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        #将二维矩阵转为1维的二进制列表
        #这个地方的base=2表示二进制,base=10就表示十进制,一次类推
        nums = [int(''.join(item),base=2) for item in matrix]
        #设定初始值res,用来保存最大的变长
        #n是二进制列表的长度
        res,n = 0,len(nums)
        for i in range(n):    
            temp = nums[i]
            for j in range(n):
                #进行与操作
                temp = temp&nums[j]
                #得到宽度
                w = self.getWidth(temp)
                #得到长度
                h = j-i+1
                #如果w<h了,那就不需要在更新h了,因为h是不断变大的,而我们只需要求w和h的最小值
                if w<h:
                    break
                #更新最大边长
                res = max(res,min(h,w))
        return res**2

 

2、动态规划算法

clas Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        low = len(matrix)
        cloum = len(matrix[0])
        #为了方便计算所以声明一个dp,比原矩阵多一列多一行,为了求左上角和上左的位置不出界
        dp = [[0]*(cloum+1) for _ in range(low+1)]
        #用来保存最大的边长
        res = 0
        for i in range(1,low+1):
            for j in range(1,cloum+1):
                #如果原矩阵的位置为1,查看左上角、左、上是不是都不为0.如果是的话那么进行更新
                #如果不是遍历矩阵的下一个元素,只有原矩阵位置是1才更行dp,否则就是0
                if matrix[i-1][j-1]=='1':
                    '''
                    if dp[i-1][j-1] and dp[i-1][j] and dp[i][j-1]:
                        dp[i][j] = min(dp[i-1][j-1],dp[i-1,j],dp[i][j-1])+1
                    else:
                        dp[i][j] = 1
                    '''
                    #动态转移方程
                    dp[i][j] = min(dp[i-1][j-1],dp[i-1,j],dp[i][j-1])+1
                    res = max(res,dp[i][j])
        return res**2

总结:昨天打卡的这个题,我还是觉得第一个更巧妙一些。灵活的运用了二进制运算方法去求解,十分巧妙。动态规划是一个很重要的解题思路,既然不能规避,那就彻底搞明白它。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值