计算01数组的最大正方形/矩形面积

数组如下:

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

思想:动态规划

dp[i][j]表示以第(i, j)个元素作为正方形右下角时最大正方形的边长

状态转移方程:

matrix[i][j]==1dp[i][j] = 1+min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1])

matrix[i][j]==0dp[i][j] = 0

class Solution:
    def maximalSquare(self, matrix: list) -> int:
        if not matrix:
            return 0
        M, N = len(matrix), len(matrix[0])
        dp = [[0 for i in range(N)] for j in range(M)]
        for i in range(M):
            dp[i][0] = 1 if matrix[i][0] == 1 else 0  # 初始化第1列
        for j in range(N):
            dp[0][j] = 1 if matrix[0][j] == 1 else 0  # 初始化第1行

        for i in range(1, M):
            for j in range(1, N):
                if matrix[i][j] == 1:
                    dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1
        maxValue = 0
        for i in range(M):
            maxValue = max(max(dp[i]), maxValue)
        print(maxValue)
        return maxValue ** 2

s = Solution()
x = s.maximalSquare([[1,0,1,0,0],[1,0,1,1,1],[1,1,1,1,1],[1,0,0,1,0]])
print(x)
# 输出: 4

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

2.1. 思想:直方图。

先行题:计算直方图的最大面积   输入:heights = [2, 1, 5, 6, 2, 3],输出:10

分析:

(1)计算以第i个值作为矩形高的时候,最大的底边长是多少。需要记录left和right的索引,然后底边长为\small width[i] = right[i] - left[i] - 1,对应面积为 \small area[i] = heights[i] \times width[i]

(2)初始化左右边界,\small left[i] = -1, right[i] = len(heights)

(3)使用单调栈。当栈顶元素比第i个元素值大的时候,即\small heights[stack[-1]] >= heights[i],该栈顶元素的右边界确定为\small right[stack[-1]] = i,然后将栈顶元素弹出。

(4)重复(3),直到栈顶元素\small heights[stack[-1] ] < heights[i]时,更新左边界\small left[i] = stack[-1];如果栈空则使用初始值就好,最后将索引i入栈。

这样就可以找到比自己矮的矩形索引作为边界条件!!!

如图,以5为高的矩形边界 left = 1, right =4, width = 4-1-1=2, area = 2*5 = 10

# 空间复杂度O(n)
# 时间复杂度O(n)
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        if not heights:
            return 0
        left = [-1] * len(heights)
        right = [len(heights)] * len(heights)
        stack = []
        for i in range(len(heights)): # 往左遍历
            while stack and heights[stack[-1]] >= heights[i]:
                k = stack.pop(-1)
                right[k] = i
            left[i] = stack[-1] if stack else -1
            stack.append(i)
        area = max([heights[i]*(right[i]-left[i]-1) for i in range(len(heights))])
        return area

计算出直方图面积之后,就可以对01数据进行分析了。

状态转移方程为

但是其实dp[i]存储的时某一行的直方图heights!!!只需要申请1*n的空间就可以了,不需要m*n。

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        if not heights:
            return 0
        left = [-1] * len(heights)
        right = [len(heights)] * len(heights)
        stack = []
        for i in range(len(heights)):
            while stack and heights[stack[-1]] >= heights[i]:
                k = stack.pop(-1)
                right[k] = i
            left[i] = stack[-1] if stack else -1
            stack.append(i)
        area = max([heights[i]*(right[i]-left[i]-1) for i in range(len(heights))])
        return area

    def maximalRectangle(self, matrix: List[List[str]]) -> int:

        if not matrix:
            return 0
        # dp[i][j]用来存储当前以(i,j)为底的柱状高度,但是为了节省空间,使用dp[j]代替二维数组
        dp = [0]*len(matrix[0])
        
        for j in range(len(matrix[0])):
            dp[j] = 1 if matrix[0][j] == '1' else 0
        
        maxArea = self.largestRectangleArea(dp)
        for i in range(1, len(matrix)):
            for j in range(len(matrix[0])):
                dp[j] = dp[j] + 1 if matrix[i][j] == '1' else 0
            maxArea = max(maxArea, self.largestRectangleArea(dp))
        return maxArea

 

2.2. 思想:动态规划。和求最大正方形不同,dp列表需要存储两个值 高和宽

——(下面的是错的,目前还没想到好方法,但是hr告诉我可以这样操作,我也很头疼!!!)

分析:

(1)求dp第一行时,存在矩阵时高度只能为1;求dp第一列时,存在矩阵时宽度只能为1。不存在时高和宽都为0。

(2)从i=1,j=1下标开始动态规划。

如果matrix[i][j]==0,则dp[i][j]=(0,0)

如果matrix[i][j]==1,则要分情况讨论:

A. 如果matrix[i-1][j-1]==0,那么只可能从列矩形(宽为1)或行矩形(高为1)中选取面积最大的一种。

 

对于matrix[1][2]元素,由于matrix[0][1]==0,因此只能选取红色框的列矩形或者蓝色框的行矩形,很明显,红色矩形面积更大,因此dp[1][2]=(2,1),即

如果行矩形面积更大,则

B. 如果matrix[i-1][j-1]==1,那么

显然,元素(2,4)作为矩形右下角,可以到最大面积就是2*3=6

class Solution:
    def maximalSquare(self, matrix: list) -> int:
        if not matrix:
            return 0
        M, N = len(matrix), len(matrix[0])
        dp = [[[0, 0] for i in range(N)] for j in range(M)]

        # 求dp[0][0]元素
        if matrix[0][0] == 1:
            dp[0][0] = [1,1]

        # 求dp第一行
        for i in range(1, M):
            if matrix[i][0] == 1:
                dp[i][0][0] = dp[i - 1][0][0] + 1
                dp[i][0][1] = 1
        # 求dp第一列
        for j in range(1, N):
            if matrix[0][j] == 1:
                dp[0][j][0] = 1
                dp[0][j][1] = dp[0][j-1][0] + 1

        maxValue = 0 # 记录最大面积
        for i in range(1, M):
            for j in range(1, N):
                if matrix[i][j] == 1:   # 如果第(i,j)个元素为1,才更新dp矩阵 
                    if matrix[i-1][j-1] == 0:  # 检查(i-1, j-1)元素是否为0,如果为0的话,则只选取最大的那个矩阵高和宽存储
                        if dp[i - 1][j][0] >= dp[i][j-1][1]:  # 如果列矩阵面积更大,更新高
                            dp[i][j][0] = dp[i - 1][j][0] + 1
                            dp[i][j][1] = 1
                        else:    # 如果行矩阵面积更大,更新宽
                            dp[i][j][0] = 1
                            dp[i][j][1] = dp[i][j-1][1] + 1
                    else:# 如果(i-1, j-1)元素为1,则高和宽都更新
                        dp[i][j][0] = dp[i - 1][j][0] + 1
                        dp[i][j][1] = dp[i][j - 1][1] + 1
                    maxValue = max(dp[i][j][0] * dp[i][j][1], maxValue)

        return maxValue  # 返回最大面积

s = Solution()
x = s.maximalSquare([[1, 0, 1, 0, 0], [1, 0, 1, 1, 1], [1, 1, 1, 1, 1], [1, 0, 0, 1, 0]])

print(x)
# 输出6  (因为2*3=6)

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值