在0-1矩阵中找到1的最大面积存在问题。在这个问题中有两种情况:
要测量的区域是形状正方形。 DP很简单。
要测量的区域是矩形的形状。我无法为此考虑最佳解决方案。
示例:
010101
101001
111101
110101
最大的矩形的面积为4(第3行,第5列,第3行,第4行)。我们还可以获得所有那些矩形吗?
答案 0 :(得分:18)
我将逐步介绍一些增加难度/降低运行时复杂性的解决方案。
首先,蛮力解决方案。生成每个可能的矩形。你可以通过迭代每对点(r1,c1)(r2,c2)来实现这一点,其中r1≤r2和c1≤c2(可以用4个for循环完成)。如果矩形不包含0,则将该区域与到目前为止找到的最大区域进行比较。这是O(R ^ 3C ^ 3)。
我们可以将有效的矩形检查加速到O(1)。我们通过做一个DP来做到这一点,其中dp(r,c)存储矩形中的0的数量((1,1),(r,c))。
然后((r1,c1),(r2,c2))中的0的数量为
然后您可以通过nzeroes(r1,c1,r2,c2)== 0检查矩形是否有效。
使用简单的DP和堆栈,有一个O(R ^ 2C)解决方案。通过查找单元格上方1个单元格的数量直到下一个0,DP每列工作.dp如下:
然后执行以下操作:
area = 0
for each row r:
stack = {}
stack.push((height=0, column=0))
for each column c:
height = dp(r, c)
c1 = c
while stack.top.height > height:
c1 = stack.top.column
stack.pop()
if stack.top.height != height:
stack.push((height=height, column=c1))
for item in stack:
a = (c - item.column + 1) * item.height
area = max(area, a)
也可以使用三个DP来解决O(RC)中的问题:
三个复发关系是:
h(r,c)= h(r-1,c)+1否则
l(r,0)= 0
l(r,c)= min(l(r - 1,c),c - p)否则
r(r,C + 1)= 0
其中p是前一个0的列,因为我们从左到右填充l,从右到左填充r。
答案是:
这是有效的,因为观察到最大的矩形将始终在所有四个边上接触0(考虑边缘被0覆盖)。通过考虑至少顶部,左侧和右侧接触0的所有矩形,我们覆盖所有候选矩形。生成每个可能的矩形。你可以通过迭代每对点(r1,c1)(r2,c2)来实现这一点,其中r1≤r2和c1≤c2(可以用4个for循环完成)。如果矩形不包含0,则将该区域与到目前为止找到的最大区域进行比较。
注意:我从我写的here的答案中对上述内容进行了调整 - 请参阅“本的妈妈”部分。在那篇文章中,0是树。该文章也有更好的格式。
答案 1 :(得分:2)
可以将问题简化为在直方图中多次查找最大矩形区域。
在每一行之后,您计算直到该行构建的直方图,并计算该直方图中的最大面积矩形。
int maximalRectangle(vector<vector<char> > &mat) {
int rows=mat.size();
if(rows==0)return 0;
int columns = mat[0].size();
int temp[columns];
for(int i=0;i<columns;i++){
temp[i] = mat[0][i]-'0';
}
int maxArea=0;
maxArea = max(maxArea,maxUtil(temp,columns));
// cout<<"before loop\n";
// print1d(temp,columns);
for(int i=1;i<rows;i++){
for(int j=0;j<columns;j++){
temp[j] = (mat[i][j]-'0')?temp[j]+1:0;
}
// cout<<"after iteration : "<<i<<endl;
// print1d(temp,columns);
maxArea = max(maxArea,maxUtil(temp,columns));
// cout<<"maxarea = "<<maxArea<<endl;
}
return maxArea;
}
temp是每个步骤中的直方图,maxutil计算该直方图中的最大矩形区域。
答案 2 :(得分:1)
我会尝试以下方法:
(1)将矩阵分解为连通分量(通过BFS)。
(2)对于每个连接的组件,查找最大矩形。
要做(2),我首先要寻找垂直矩形:找到每个连续(min_y,max_y)的最大可能宽度,从而找到该区域(迭代地,每行O(1),只需查看连接组件的那一行中的最小值/最大值1。 然后我将转置矩阵,并重复该过程。
BFS的总运行时间为O(MxN),然后是每个连接的组件的O(宽度^ 2 +高度^ 2),总计为O(MXN + M ^ 2 + N ^ 2)。
我想知道什么是渐近最优解决方案。
答案 3 :(得分:0)
**
//use this dynamic programming approach
//The problem can be reduced to finding the maximum rectangle area in a histogram, multiple times.
After each row, you calculate the histogram built until that row, and that calculate the maximum area rectangle in that histogram.
**
import java.util.Scanner;
public class LargestRectInAmatrix {
static int row,col,matrix[][];
static int maxArea=0;
static int barMatrix[];
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
row=sc.nextInt();
col=sc.nextInt();
matrix=new int[row][col];
barMatrix=new int[col];
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
matrix[i][j]=sc.nextInt();
}
}
startSolution();
System.out.println(maxArea);
}
private static void startSolution()
{
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
if(matrix[i][j]==0)
{
barMatrix[j]=0;
}
else
barMatrix[j]=barMatrix[j]+matrix[i][j];
}
int area=calculateArea(0,col-1);
if(area>maxArea)
{
maxArea=area;
}
}
}
private static int calculateArea(int l,int h)
{
if(l>h)
{
return Integer.MIN_VALUE;
}
if(l==h)
{
return barMatrix[l];
}
int u=calMinimumIndex(l,h);
return (max(calculateArea(l, u-1),calculateArea(u+1, h),barMatrix[u]*(h-l+1)));
}
private static int max(int a,int b,int c)
{
if(a>b)
{
if(a>c)
{
return a;
}
else
return c;
}
else
if(b>c)
{
return b;
}
else
return c;
}
private static int calMinimumIndex(int l,int h)
{
int min=Integer.MAX_VALUE;
int min_index=0;
for(int i=l;l<=h;i++)
{
if(barMatrix[i]<min){
min=barMatrix[i];
min_index=i;
}
}
return min_index;
}
}
答案 4 :(得分:0)
另一种更简单的方法是使用两个临时M x N阵列来计算矩形的长度(行和列方式) - 即连续1的计数。遍历两个临时矩阵以找到最大重复长度(行和列方式)。
以下是相同的代码。
int GetMaxRectangularArea(vector<vector<int>> & matrix, int nRows, int nCols)
{
vector<vector<int>> rowLengths(nRows, vector<int>(nCols));
vector<vector<int>> colLengths(nRows, vector<int>(nCols));
// initialize first column of rowLengths with first column of matrix
for (int i = 0; i < nRows; i++) {
rowLengths[i][0] = matrix[i][0];
}
// initialize first row of colLengths with first row of matrix
for (int j = 0; j < nCols; j++) {
colLengths[0][j] = matrix[0][j];
}
// Compute row wise length of consecutive 1's in rowLengths
for (int i = 0; i < nRows; i++) {
for (int j = 1; j < nCols; j++) {
if (matrix[i][j] == 1) {
rowLengths[i][j] = 1 + rowLengths[i][j - 1];
}
else {
rowLengths[i][j] = 0;
}
}
}
// Compute column wise length of consecutive 1's in colLengths
for (int j = 0; j < nCols; j++) {
for (int i = 1; i < nRows; i++) {
if (matrix[i][j] == 1) {
colLengths[i][j] = 1 + colLengths[i- 1][j];
}
else {
colLengths[i][j] = 0;
}
}
}
// Now traverse the rowLengths array to find max length sub array
int maxArea = 0;
for (int j = nCols - 1; j >= 0; j--) {
int currentArea = 0;
int currentMax = -1;
int repeats = 1;
for (int i = nRows - 1; i >= 0; i--) {
if (rowLengths[i][j] != currentMax) {
if (currentMax != -1) {
currentArea = currentMax * repeats;
if (currentArea > maxArea) {
maxArea = currentArea;
}
}
currentMax = rowLengths[i][j];
repeats = 1;
}
else {
repeats++;
}
}
currentArea = currentMax * repeats;
if (currentArea > maxArea) {
maxArea = currentArea;
}
}
for (int i = nRows - 1; i >= 0; i--) {
int currentArea = 0;
int currentMax = -1;
int repeats = 1;
for (int j = nCols - 1; j >= 0; j--) {
if (colLengths[i][j] != currentMax) {
if (currentMax != -1) {
currentArea = currentMax * repeats;
if (currentArea > maxArea) {
maxArea = currentArea;
}
}
currentMax = colLengths[i][j];
repeats = 1;
}
else {
repeats++;
}
}
currentArea = currentMax * repeats;
if (currentArea > maxArea) {
maxArea = currentArea;
}
}
return maxArea;
}
答案 5 :(得分:0)
class GfG{
public int maxArea(int a[][],int m,int n){
if(a==null || m==0 || n== 0) return 0;
m = a.length;
n = a[0].length;
int dp[] = new int[n+1];
int height[] = new int[n];
int p = 0;
dp[p] = -1;
int ans = 0;
//System.out.println("1 ");
for(int i = 0;i<m;i++){
for(int j = 0;j<n;j++){
if(a[i][j]==1){
height[j] += a[i][j];
}
else{
height[j] = 0;
}
}
p= 0;
//System.out.println("2 ");
for(int j = 0;j<n;j++){
while(p>0 && height[j] < height[dp[p]]){
int start = dp[p-1];
ans = Math.max(ans,(j-start-1)*height[dp[p]]);
p--;
//System.out.println("1 ");
}
dp[++p] = j;
}
}
return ans;
}
}