【算法】求解最大子矩阵的大小:给定一个整型矩阵,其中的值只有0和1两种,求其中全是1的所有矩形区域中,最大的矩形区域为1的数量。

求解最大子矩阵的大小
【题目】
给定一个整型矩阵,其中的值只有0和1两种,求其中全是1的所有矩形区域中,最大的矩形区域为1的数量。
例如:
1 1 1 0
其中,最大的矩形区域有3个1,所以返回3。再如:
1 0 1 1
1 1 1 1
1 1 1 0
其中,最大的矩形区域有6个1,所以返回6。

思路:

先计算以data[i]为底的矩阵大小,
例如:
1 0 1 1
1 1 1 1
1 1 1 0
以第一行为底,大小[1,0,1,1]
第二行为底,大小[2,1,2,2]
第三行为底,大小[3,2,3,0]
遇到0就置为0,故用 height[i] = data[i*cols+j]==0 ? 0 : height[i]+1; 如果遇到0,就置0,否则,高度+1,得到一个以data[i]为底的矩阵大小;
实际上可以看作一个直方图:例如:以第三行为底,可以得到
在这里插入图片描述
转化为在直方图的计算就是,以同一边作为底,当前最大能覆盖的矩阵面积:
注意
每一个计算得到的直方图,都需要进行计算一下最大矩阵,例如用例4:
在这里插入图片描述
显然,第二三四五行中,得到的height矩阵,都是[0,0,0,0,0]
最大矩阵在第一行,

接下来计算最大矩阵:
例如 h e i g h t [ ] = { 1 , 4 , 3 , 2 , 4 , 5 } height[] = \{1,4,3,2,4,5\} height[]={ 1,4,3,2,4,5}
定义栈stack,

  1. 当前栈为空,或者遇到一个比当前栈顶大的值,压栈(放入坐标i,而不是height[i])。这样一来,栈里的坐标标注的矩阵,就都是递增的矩阵了。
    在这里插入图片描述

例如这里的1,4,就可以直接入栈了,此时栈中是他们所在的坐标: [ 0 , 1 ] [0,1] [0,1]

  1. 遇到一个和当前栈顶一样大,或者比当前栈顶小的值:
    i f ( ! s t a c k . e m p t y ( )    & &     h e i g h t [ i ] < = h e i g h t [ s t a c k . t o p ( ) ] ) if(!stack.empty()\ \ \&\& \ \ \ height[i]<=height[stack.top()]) if(!stack.empty()  &&   height[i]<=height[stack.top()])
    说明矩阵大小开始收缩了,
    此时以当前遍历到的j = stack.top()为中心,向左右进行扩展
    在这里插入图片描述
    此时遇到了3,j = stack.top(),所以j=1
    可以计算高度为4的矩阵的最大大小了,
    这里,4向左,只能遍历到坐标为1的位置,也就是它自身
    4向右,只能遍历到左边为1的位置,也就是它自身
    所以4所在位置的最大矩阵大小只能是4;
    此时,栈中,j被弹出,再压入当前i,修改后的坐标为: [ 0 , 2 ] [0,2] [0,2]

  2. 可知若 h e i g h t [ i ] < h e i g h t [ s t a c k . t o p ( ) ] height[i]<height[stack.top()] height[i]<height[stack.top()], j向右,最多遍历到i-1 。因为如果可以遍历到i,那就可以直接继续压栈了,由于height[i]<=height[stack.top()] 而且j = stack.top(),所以最多能遍历到i-1

  3. 如果 h e i g h t [ i ] = = h e i g h t [ s t a c k . t o p ( ) ] height[i]==height[stack.top()] height[i]==height[stack.top()] 那么其实j向右,是可以压栈到i的,我们没有必要计算两次,因为i出栈的时候,也会计算一次向左的矩阵大小,显然这个矩阵是包含了j的。

  4. j位置向左,最多可以扩展到新的栈顶k+1的位置,因为当前栈里面的矩阵高度一定是递增的,显然,height[k]<height[j],所以此时可以得到,在j位置,最大矩阵面积是 ( i − k − 1 ) ∗ h e i g h t [ j ] (i-k-1)*height[j] (ik1)height[j]

  5. 注意,只有在出栈时,才会计算最大矩形的面积。
    index = 3 时,height[3] = 2,此时stack中有 [ 0 , 2 ] [0,2] [0,2],可知,以index=2的矩阵,向左有最大矩阵S = ((i-k-1)*height[j]) = 6
    在这里插入图片描述

  6. 当i已经到了height矩阵的最后一个元素,可以令k=-1,i=height.length,继续计算出栈j的值,直到栈中为空为止。

c++

#include <iostream>
#include <stack>
using namespace std;
/**
**  获取以height为底的矩形的最大面积
**/
int GetMaxArea(int* height, int length) {
    
    
	stack<int> s;
	int j = 0, k = 0;
	int maxArea = 0;
	
	int i = 0;
	while (i<length || !s.empty())
	{
    
    
		while (!s.empty() && height[i] <= height[s.top()])
		{
    
    
			j = s.top();
			s.pop();
			if (s.empty())
			{
    
    
				k = -1;
			}
			else {
    
    
				k = s.top();
			}
			maxArea = max(maxArea, (i - k - 1) * height[j]);
		}
		if (i<length)
		{
    
    
			s.push(i);
			i++;
		}
	}
		
	return maxArea;
}

/**
*  获取最大子矩阵的面积大小
**/
int GetMaxSubMatrixArea(int* data,int rows,int cols) {
    
    
	if (data==nullptr||rows<=0||cols<=0)
	{
    
    
		return 0;
	}
	int* height = new int[cols];
	for (int i = 0; i < cols; i++)
	{
    
    
		height[i] = 0;
	}
	int max = 0,area = 0;
	for (int i = 0; i < rows; i++)
	{
    
    
		for (int j = 0; j < cols; j++)
		{
    
    
			height[j] = data[i * cols + j] == 0? 0 :height[j] + 1  ;
		}
		area = GetMaxArea(height, cols);
		if (max<area)
		{
    
    
			max = area;
		}
	}
	return max;
}


void GetMaxSubMatrixArea_Test() {
    
    

	int data[] = {
    
     1,0,1,1,
				   1,1,1,1,
				   1,1,1,0 };
	// 6 
	cout << GetMaxSubMatrixArea(data, 3, 4) << endl;


	int data2[] = {
    
     1,0,1,1,
					0,1,1,0,
					1,1,1,1,
					0,1,1,1,
					1,1,1,1 };
	// 9 
	cout << GetMaxSubMatrixArea(data2, 5, 4) << endl;


	int data3[] = {
    
     1,0,0,1,0,
					0,1,1,0,1,
					1,1,1,1,1,
					1,1,1,1,0,
					0,1,1,0,0 };
	// 8
	cout << GetMaxSubMatrixArea(data3, 5, 5) << endl;


	int data4[] = {
    
     0,1,1,1,1,
					0,0,0,0,0,
					0,0,0,0,0,
					0,0,0,0,0,
					0,0,0,0,0 };
	// 4
	cout << GetMaxSubMatrixArea(data4, 5, 5) << endl;


	int data5[] = {
    
     0,1,1,1,1,
					0,0,1,0,0,
					0,0,1,0,0,
					0,0,1,0,0,
					0,0,1,0,0 };
	// 5
	cout << GetMaxSubMatrixArea(data5, 5, 5) << endl;

	int* data6 = nullptr;
	// 0 异常输入
	cout << GetMaxSubMatrixArea(data6, 0, 0) << endl;
}

int main()
{
    
    
	GetMaxSubMatrixArea_Test();
}

猜你喜欢

转载自blog.csdn.net/qinglingLS/article/details/123938546