2019牛客暑期多校训练营(第二场) H Second Large Rectangle 【次大全1子矩阵和】【单调栈】
题意
在01矩阵中找到第二大的全1矩阵,若没有第二大的矩阵则输出0。
题目链接:
https://ac.nowcoder.com/acm/contest/882/H
题解
这个题目题意看起来很简单,但是真的把我打自闭了,矩阵n,m大小在1~1000。如果暴力的话O(n3)还是会TLE的。
以下讲讲我的思路。搞清楚第二大矩阵,首先我们要解决的问题是:
-
怎么判断矩阵
-
怎么找到最大矩阵
-
怎么找到第二大矩阵
一、判断矩阵的方法很简单,我们只要确保矩阵里面全是1就好了。
二、找到最大矩阵有一点小技巧。
举例来说:5*5的矩阵
1 1 1 1 1
1 1 1 1 0
1 1 1 0 0
1 1 0 0 0
1 1 0 0 0
我们定义一个数组h来记录这个矩阵的高,从上加到下,如果为0则定义为0,那么h矩阵就是:
1 1 1 1 1
2 2 2 2 0
3 3 3 0 0
4 4 0 0 0
5 5 0 0 0
以h矩阵的h[i][j]为矩阵的左下角,用数字d当作矩阵的宽度,从1开始递增(直到右边的数为比他小为止)矩阵的大小则为d*h。
三、找到第二大的矩阵其实很简单
用max1和max2来记录矩阵的最大值和一个比最大值小的数。然后再去维护这两个数,遇到比最大值大的就修改最大值,遇到在两个数之间的就修改第二个值。
所以我们可以算出所有矩阵的大小,然后通过max1和max2来找到第二大的矩阵
没错,虽然说我的思路很清晰,但是还是搞不定呀。。。
询问过学长后才知道需要用【单调栈】来优化算法
单调栈
单调栈顾名思义就是栈里面的元素都是单调性的(单调增或单调减)
这里用单调栈储存数组的下标。j从1遍历到m,如果h[j]<h[栈顶]的话就计算该矩阵的面积,然后将栈顶元素弹出,再重复比较h[j]和h[栈顶]。最后把h[j]压入栈中。
由于使用单调栈,我们求得是最大子矩阵,所以要把包含在最大子矩阵得次大
子矩阵的情况算进去,所以对于取值的时候要特判 (d-1,h) 和 (d,h-1),d代表底,h代表高。
例如:2*3的矩阵
1 1 0 0
1 1 1 1
h矩阵为:
1 1 0 0
2 2 1 1
i = 1时:先将0压入栈中,再将1、2压入栈中,栈的元素为0 1 2 。
因为h[3] == 0 < 1,所以计算面积 max1= 1,max2 = 2。
i = 2时:先将0压入栈中,再将1、2压入栈中,栈的元素为0 1 2 。
因为h[3] == 1 < 2,所以计算面积 max1= 2,max2 = 4。
然后栈的元素再变为0 3 4,当4后面没有数了,直接计算。
最后算出面积是 max1= 4,max2 = 4。
AC代码
#include<string.h>
#include<stdio.h>
#include<stack>
#include<algorithm>
using namespace std;
int matrix[1005][1005];
int h[1005];
int r[1005];
int l[