leetcode 85 暴力+dp+单调栈 无敌题目

在这里插入图片描述

解法一:中等暴力
提前预存好每个竖的连续区间是否全为1,并利用此信息,可使暴力复杂度达到O(N 2 ^2 2M 2 ^2 2),代码如下:

import numpy as np
class Solution:
    def maximalRectangle(self, matrix: List[List[str]]) -> int:
        if matrix == []: return 0

        rows, cols = len(matrix), len(matrix[0])
        ret = 0

        one = np.zeros((cols, rows, rows), dtype=np.int32)
        # init
        for j in range(cols):
            for i in range(rows):
                for p in range(i, rows):
                    if matrix[p][j] == '1':
                        one[j][i][p] = 1
                    else: break

        # 搜索
        for i in range(rows):
            for j in range(cols):
                if matrix[i][j] == '0': continue
                for p in range(i, rows):
                    if matrix[p][j] == '0': break
                    for q in range(j, cols):
                        if one[q][i][p]:
                            if (q-j+1)*(p-i+1) > ret:
                                ret = (q-j+1)*(p-i+1)
                        else: break

        return ret

解法二:再优化暴力
这次咱们存好向右的最大长度,就不用一个一个遍历了。可让复杂度变为O(M 2 ^2 2N)。其中,计算最长连续1个数时,可以用dp的思想实现快速计算。和马拉车算法有些类似,都看最长的是不是包含了,不过这个简单很多。再程序的第二部分,我们的做法是遍历所有柱子并记录每个柱子出发的最小值,比较暴力。到这一步,其实已经和84题类似了。

class Solution:
    def maximalRectangle(self, matrix: List[List[str]]) -> int:
        if len(matrix) == 0 or len(matrix[0]) == 0: return 0
        
        ret = 0
        rows, cols = len(matrix), len(matrix[0])
        continue_ones = [[0 for _ in range(cols)] for _ in range(rows)]
        # 构建
        for i in range(rows):
            for j in range(cols):
                if i > 0 and matrix[i-1][j] == '1':
                    continue_ones[i][j] = continue_ones[i-1][j]-1
                    continue
                for p in range(i, rows):
                    if matrix[p][j] == '1':
                        continue_ones[i][j] += 1
                    else: break

        # 搜索
        for i in range(rows):
            for j in range(cols):
                if matrix[i][j] == '0': continue

                mi = rows
                for p in range(j, cols):
                    if continue_ones[i][p] == 0:
                        break

                    if continue_ones[i][p] < mi:
                        mi = continue_ones[i][p]
                    
                    if mi*(p-j+1) > ret:
                        ret = mi*(p-j+1)

        return int(ret)

解法三:单调栈
利用84题单调栈的思想求中心扩散长度,可以在O(MN)复杂度内计算出结果。其中,dp数组由于可以用dp生成,可以用O(N)的空间来存储。这样我们就可以得到一个O(MN)的算法。

class Solution:
    def maximalRectangle(self, matrix: List[List[str]]) -> int:
        if len(matrix) == 0 or len(matrix[0]) == 0: return 0
        
        ret = 0
        rows, cols = len(matrix), len(matrix[0])
        dp = [0 for _ in range(cols+2)] # 表示在任意一行,该位置连续向下的1的个数
        # 构建
        for i in range(rows-1, -1, -1):
            for j in range(cols):
                if matrix[i][j] == '0': dp[j+1] = 0
                else: dp[j+1] += 1

            # 搜索
            stack = []
            for j, num in enumerate(dp):
                while stack and num < dp[stack[-1]]:
                    val = (j-stack[-2]-1)*dp[stack[-1]]
                    if val > ret: ret = val
                    stack.pop()
                stack.append(j)

        return ret

此时代码已经很简短了,而且搜索算法用的是84题最快的单调栈解法,代码干净又强大。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值