【LeeCode】85. 最大矩形 三种方法,引申和思考

33 篇文章 0 订阅
21 篇文章 3 订阅

【1】点此前往挑战
参考网址:
[1]Leecode最大矩形思路
[2]详细通俗的思路分析,多解法

美团这个题把 {} 改为 [] ,用python 的eval()转为列表,后面的做法和最大矩形一样。

1.暴力破解:
  • 遍历每一行,求解高度为1的矩形 连续1 的个数,并且更新数组中的该值。
    在这里插入图片描述
  • 向上扩展一行,高度增加一,选出 当前列最小的数字 (图中四所在列最小是2,面积2*2),作为矩阵的宽,求出面积,对应上图的矩形框。(可知列最小的数字决定了左边界)
  • 然后继续向上扩展,重复步骤 2。算出所有高度(1,2,3,4)的情况。
  • 遍历所有的点,求出所有的矩阵就可以了。

不过由于复杂度太高,会导致超时

class Solution:
    def maximalRectangle(self, matrix) -> int:
        inp=matrix
        save=[[0 for i in range(len(inp[0]))]for i in range(len(inp))]
        # 计算高度为1时的宽度矩阵
        for j in range(0,len(inp)):
            width=0
            for k in range(0,len(inp[0])):
                if int(inp[j][k])==1:
                    width+=1
                    save[j][k]=width
                else:
                    width=0
        # print(save)
        max=0
        if len(save)!=0 and len(save[0])!=0:
            max=save[0][0]
        for i in range(1,len(inp)+1): # i表示高度
            # 计算高度为i时的宽度
            for j in range(0,len(inp)-i+1):# 高度为i,列方向移动len(inp)-i+1次
                width=0
                for k in range(0,len(inp[0])): 
                    # 选出当前列最小的数字
                    min = save[j][k]
                    for p in range(j,j+i): # 固定行,遍历列选出最小
                        if min>save[p][k]:
                            min=save[p][k]
                    tmp=min*i # 当前列最小的数字作为矩阵的宽,高度是i,求出面积
                    if(tmp>max):
                        max=tmp   
        print(max)
        return max
s= Solution()
inp=[["1"]]
s.maximalRectangle(inp)  
  • 长为 m m m,宽(高)为 n n n
  • 时间复杂度: O ( m ∗ n + n ∗ n ∗ m ) = O ( m ∗ n 2 ) O(m*n+n*n*m)=O(m*n^2) O(mn+nnm)=O(mn2)
  • 空间复杂度: O ( m ∗ n ) O(m*n) O(mn)
2.利用单调栈:

[1]利用类似题目,之前写的博文——求一个直方图矩形的最大面积。
其实也就是求高度(1,2,3,4)不同情况下的最大直方图矩形面积。若底为0,就在直方图里标1,否则标0
在这里插入图片描述
代码:
在这里插入图片描述

class Solution:
    def calcu_max_rec(self,heights):
        stack=[] # 这里把0设置为heights的边界,压栈弹栈时使得边界条件不为空
        heights=[0]+heights+[0] 
        res=0
        for i in range(0,len(heights)):
            while stack and heights[stack[-1]]>heights[i]: # 出现了递减,重复弹栈
                tmp = stack.pop()
                res = max(res,(i-stack[-1]-1)*heights[tmp]) # 弹出后,栈顶为左边界,i是右边界,高度是弹栈的矩形高度
            stack.append(i)
        return res

    def maximalRectangle(self, matrix) -> int:
        if len(matrix)==0 or len(matrix[0])==0:
            return 0
        heights=[0]*len(matrix[0])
        max_size=0
        for i in range(0,len(matrix)):
            for j in range(0,len(matrix[0])):
                # print(matrix[i][j])
                if int(matrix[i][j])>=1:
                    heights[j]+=1
                else:
                    heights[j]=0
            # print(heights)

            tmp=self.calcu_max_rec(heights)
            if max_size<tmp:
                max_size=tmp
        return max_size
s=Solution()
matrix=[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
print(s.maximalRectangle(matrix))
  • 长为 m m m,宽(高)为 n n n
  • 时间复杂度 O ( m ∗ n ) O(m*n) O(mn)
  • 空间复杂度 O ( m ) O(m) O(m)
3.动态规划方法:

参考网址:[1]动态规划 - 每个点的最大高度
直觉
想象一个算法,对于每个点我们会通过以下步骤计算一个矩形:

  • 不断向上方遍历,直到遇到“0”,以此找到矩形的最大高度。
  • 向左右两边扩展,直到无法容纳矩形最大高度。

给定一个最大矩形,其高为 h, 左边界 l,右边界 r,在矩形的底边,区间 [l, r] 内必然存在一点,其上连续1的个数(高度)<=h。若该点存在,则由于边界内的高度必能容纳 h,以上述方法定义的矩形会向上延伸到高度 h,再左右扩展到边界 [l, r] ,于是该矩形就是最大矩形。
若不存在这样的点,则由于[l, r]内所有的高度均大于 h,可以通过延伸高度来生成更大的矩形,因此该矩形不可能最大。

  • 综上,对于每个点,只需要计算hl,和 r - 矩形的高左边界右边界
  • 使用动态规划,我们可以在线性时间内用上一行每个点的 hl,和 r 计算出下一行每个点的的h,l,和r

算法:
总而言之, 要找尽可能大的高度,尽可能左的左边界,尽可能右的右边界。

代码:
在这里插入图片描述

# 动态规划方法:
class Solution:
    def maximalRectangle(self, matrix) -> int:
        if not matrix:return 0
        height=len(matrix)
        width=len(matrix[0])
        heights=[0]*width
        left=[0]*width # 初始化左边界为最左边界
        right=[width]*width # 初始化右边界为最右边界
        
        maxarea=0
        for i in range(height):
            cur_left,cur_right=0,width
            # 更新当前行的高度
            for j in range(width):
                if matrix[i][j]=='1':heights[j]+=1
                else: heights[j]=0
            # 更新左边界
            for j in range(width):
                if matrix[i][j]=='1':left[j]=max(left[j],cur_left)
                else:
                    left[j]=0
                    cur_left=j+1  
                    # 是我们遇到的最右边的0的序号加1。当将矩形向左 “扩展” ,
                    # 不能超过该点,否则会遇到0。
            # 更新右边界
            for j in range(width-1,-1,-1):
                if matrix[i][j]=='1':right[j]=min(right[j],cur_right)
                else:
                    right[j]=width
                    cur_right=j
            # 更新最大边界
            for j in range(width):
                maxarea=max(maxarea,heights[j]*(right[j]-left[j]))
        return maxarea
                

s=Solution()
matrix=[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
print(s.maximalRectangle(matrix))

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值