leetcode 85 最大矩形

文章详细介绍了两种方法来计算矩阵中由1组成的最大矩形面积,首先是基于动态规划的暴力解法,然后是利用单调栈优化的解决方案。暴力解法虽然直观但效率较低,而单调栈方法能更高效地找到最大面积。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

遇到这种题没有好的思路,就先想着用暴力解法解决。

1.暴力解法:

利用动态规划,创建数组dp,dp存放每一行该位置的最大面积

转移方程:

当当前位置不为0,即matrix[i][j]!='0',dp[i][j] = dp[i][j-1],且j为0时,会发生数组越界情况,因此要对这种情况作特殊处理,即当matrix[i][j]!='0'且j==0时候,dp[i][j]=1

如上面的例子

 [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]

则由该方法得到的dp数组应为:

1 0 1 0 0 

1 0 1 2 3 

1 2 3 4 5 

1 0 0 1 0 

对于每个元素,从其当前行往上遍历

如对第3行第3列的元素1,遇到的第一个元素dp[3][3] = 1,即宽为width,初始化为一个较大的数,

width = min(width, dp[i][j]),由此公式可以得到第一个width为1,接着要计算高,高需要看当前行元素和遍历到的元素,记遍历元素为k,当前计算的元素位置为i,则height=(i-k+1),即为1,则此时计算出的面积area = max(area, width*height)=1,area初始化为0,继续往上遍历,即遇到dp[2][3]=4,此时width仍为1,但是height变为2,所以area变为2,一直遍历到最顶上的0元素,这样,我们就能把当前位置得到的最大面积算出来,即为3,最终返回的元素记为ret,初始化为0,每一次对某个元素遍历完后,利用公式ret=max(ret,area),在遍历完所有元素后,可以把matrix里的最大面积算出,即为ret。

Python实现如下

    def maximalRectangle(self, matrix: list[list[str]]) -> int:
        row = len(matrix)
        if row == 0:
            return 0
        col = len(matrix[0])
        dp = [[0]*col for i in range(row)] #存放每行各个元素的最大面积
        for i in range(row):
            for j in range(col):
                if matrix[i][j] != '0':
                    if j == 0:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = dp[i][j-1] + 1
                print(dp[i][j],end=' ')
            print('\n')

        #暴力解法优化 但还是过不了
        ret = 0
        for i in range(row):
            for j in range(col):
                if dp[i][j] == 0:
                    continue
                width = dp[i][j]
                area = width
                for k in range(i-1,-1,-1):
                    width = min(width, dp[k][j])
                    area = max(width*(i-k+1),area)
                ret = max(area,ret)
        print(ret)
        return area

 但暴力解法不能通过,因此另寻出路

2.单调栈

上面的算法存在的问题就是每次遍历没有利用到之前的信息,这是我们需要改善的点。

这里先将dp数组改变一下,即现在存放的是每一列该位置的最大面积。

还是上面的例子,利用改变的dp数组,我们可以得到:

1 0 1 0 0 

2 0 2 1 1 

3 1 3 2 2 

4 0 0 3 0

对每一行的元素作遍历,这里对第2行的元素[3 1 3 2 2]作讲解。

 

利用栈,若栈空我们将当前遍历的元素的下标加入栈中,若栈不空且当前的元素比栈顶元素对应的高度低,则进入循环,直到当前的元素比栈顶元素对应的高度高,计算面积,面积计算公式为(当前遍历的元素下标-栈顶元素-1)*(弹出元素对应的高度)。为避免栈空发生的越界问题,我们可以假想在最前和最尾的位置各有一个高度为-1的元素。

area初始化为0。

对于第0个元素-1,由于栈空,将其下标0加入栈中。

第1个元素3,栈顶元素对应的高度-1比3小,因此1加入栈中。

第2个元素1,栈顶元素对应的高度3比1大,将1弹出,计算高度为3对应的面积,area=max(area,(2-0-1)*3)=3,此时栈顶元素0对应的高度-1比1小,因此将下标2加入栈中。

第3个元素3,栈顶元素2对应高度1比3小,将3加入栈中。此时栈中存放[0,2,3]

第4个元素2,栈顶元素3对应高度3比2大,因此将3弹出,计算area=max(area,(4-3-1)*3)=3,此时栈顶元素2对应的高度1比2小,将下标4加入栈中。此时栈中存放[0,2,4]

第5个元素2,栈顶元素4对应高度2和2一样大,因此加入栈中,此时栈中[0,2,4,5]

第6个元素-1,栈顶元素对应高度比-1大,将5弹出,area=max(area,(5-5-1)*2)=3,此时高度还是比-1大,将4弹出,area=max(area,(6-2-1)*2)=6,此时栈[0,2],依然比-1大,将2弹出,area=max(area,(6-0-1)*1)=6,此时栈只剩下0,高度-1,则可将6加入栈中。

至此,一行的所有元素遍历完成,得到最大面积6。

记最终返回的面积为ret,初始化0,每一行遍历完成用ret=max(ret,area),在所有行遍历完后,得到的最大面积ret,将其返回即可。

Python实现如下

    def maximalRectangle2(self, matrix: list[list[str]]) -> int:
        row = len(matrix)
        if row == 0:
            return 0
        col = len(matrix[0])
        dp = [[0]*col for i in range(row)] #存放每列各个元素的最大面积
        for j in range(col):
            for i in range(row):
                if matrix[i][j] != '0':
                    if i == 0:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = dp[i-1][j] + 1
                # print(dp[i][j],end=' ')

        ret = 0
        for i in range(row):
            tmp = []
            for j in range(col):
                tmp.append(dp[i][j])
            ret = max(ret, self.maxArea(tmp))
        print(ret)
        return ret

    def maxArea(self,ar):
        n = len(ar)
        tmp = [-1] * (n+2)
        for j in range(1,n+1):
            tmp[j] = ar[j-1]

        area = 0
        stk = list()
        for i in range(n+2):
            while len(stk)>0 and tmp[stk[-1]]>tmp[i]:
                top = stk[-1]
                stk.pop()
                area = max(area, (i-stk[-1]-1)*tmp[top])
            stk.append(i)
        return area

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值