子矩阵问题
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)