算法:子矩阵问题【数组】

子矩阵问题

Description

给定一个矩形区域,每一个位置上都是1或0,求该矩阵中每一个位置上都是1的最大子矩形区域中的1的个数。

Input

输入第一行为测试用例个数。每一个用例有若干行,第一行为矩阵行数n和列数m,下面的n行每一行是用空格隔开的0或1。

Output

输出一个数值。

Sample Input 1

1
3 4
1 0 1 1
1 1 1 1
1 1 1 0

Sample Output 1

6

思路

依次以矩阵每一行j为底,往j-1结算每一列有多少个连续的1,将结果存在一个数组height[j]。例如以矩阵第三行[1,1,1,1,1]往1,2行结算,可得height[j]={3,1,3,2,2}。对于每次结算得到height[j]数组,我们可以将其看成一个直方图。如[3,1,3,2,2]可以看成如下直方图:
在这里插入图片描述
然后我们依次求出可以这个height[j]数组中最大矩形的大小maxArea是多少,依次更新这个maxArea,就可以得到结果。
思路来自:https://blog.csdn.net/u013616945/article/details/77282308
https://blog.csdn.net/wysw1998/article/details/95998122
如何求height[j]中最大矩阵呢?
根据木桶原理,其实就是求边界问题
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

python3

# 最大子矩阵问题
# 水桶原理,先构造height数组,再利用单调增栈求对应的最大面积
# 1
# 3 4
# 1 0 1 1
# 1 1 1 1
# 1 1 1 0


def get_maxArea(height):
    stack = []
    area = 0
    for i in range(len(height)):
        while len(stack) != 0 and height[stack[-1]] >= height[i]:   # 当前元素值比栈顶元素对应值小时,出栈
            j = stack.pop()
            k = -1 if len(stack) == 0 else stack[-1]
            if (i - k - 1) * height[j] > area:
                area = (i - k - 1) * height[j] 
        stack.append(i)
    # 结算栈中剩余的
    while len(stack):
        j =stack.pop()
        k = -1 if len(stack) == 0 else stack[-1]
        area = max((len(height) - k - 1) * height[j], area)  # 此时右边界为栈的长度(即height的最右边)
    return area


if __name__ == '__main__':
    nums = int(input())
    for i in range(nums):
        a, b = map(int, input().split())
        maxArea = 0
        lis = []
        for j in range(a):
            lis.append(list(map(int, input().split())))  # 构建矩阵二维列表
        height = [0 for x in range(b)]
        # 遍历求height数组,并求最大面积
        for i in range(a):
            for j in range(b):
                if lis[i][j] == 0:
                    height[j] = 0
                else:
                    height[j] += 1
            maxArea = max(get_maxArea(height), maxArea)
        print(maxArea)
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值