如何在小于 O(n^3) 的情况下找到二维布尔数组中最大的全真矩形的坐标?
How can I find the coordinates of the largest all-true rectangle in a 2d array of booleans in less than O(n^3)?
目前,我正在使用这个解决方案:
https://www.geeksforgeeks.org/maximum-sum-rectangle-in-a-2d-matrix-dp-27/
我将 true 转换为 1 & false 转换为 -infinity,然后找到最大和矩形。根据文章,这个解决方案是 O(n^3),而且它确实不够快,无法满足我的需要。我曾尝试使用最大直方图方法 (https://www.youtube.com/watch?v=g8bSdXCG-lA),但矩形大小的存储方式让我在查找最终坐标时遇到了一些麻烦。
C# 中的代码很棒,但如果需要,我很乐意采用伪代码并自己编写。
基于the link provided by the OP:
// C# program to find largest rectangle
// with all 1s in a binary matrix
using System;
using System.Collections.Generic;
class GFG {
// Finds the maximum area under the
// histogram represented by histogram.
// See below article for details.
// https:// www.geeksforgeeks.org/largest-rectangle-under-histogram/
public static (int area, int left, int right) maxHist(int C, int[] row)
{
// Create an empty stack. The stack
// holds indexes of hist[] array.
// The bars stored in stack are always
// in increasing order of their heights.
Stack<int> result = new Stack<int>();
int top_val; // Top of stack
int left;
int max_area = 0; // Initialize max area in current row (or histogram)
int max_left = -1;
int max_right = -1;
int area = 0; // Initialize area with current top
// Run through all bars of
// given histogram (or row)
int i = 0;
while (i < C) {
// If this bar is higher than the
// bar on top stack, push it to stack
if (result.Count == 0 || row[result.Peek()] <= row[i]) {
result.Push(i++);
}
else {
// If this bar is lower than top
// of stack, then calculate area of
// rectangle with stack top as
// the smallest (or minimum height)
// bar. 'i' is 'right index' for
// the top and element before
// top in stack is 'left index'
left = result.Peek();
top_val = row[left];
result.Pop();
area = top_val * i;
if (result.Count > 0) {
left = result.Peek() + 1;
area = top_val * (i - left);
}
if (area > max_area) {
max_area = area;
max_left = left;
max_right = i - 1;
}
}
}
// Now pop the remaining bars from
// stack and calculate area with
// every popped bar as the smallest bar
while (result.Count > 0) {
left = result.Peek();
top_val = row[left];
result.Pop();
area = top_val * i;
if (result.Count > 0) {
left = result.Peek() + 1;
area = top_val * (i - left);
}
if (area > max_area) {
max_area = area;
max_left = left;
max_right = C - 1;
}
}
return (max_area, max_left, max_right);
}
// Returns area of the largest
// rectangle with all 1s in A[][]
public static (int area, int top, int bottom, int left, int right)
maxRectangle(int R, int C, int[][] A)
{
int top = 0;
int bottom = 0;
// Calculate area for first row
// and initialize it as result
(int result, int left, int right) = maxHist(C, A[0]);
// iterate over row to find
// maximum rectangular area
// considering each row as histogram
for (int i = 1; i < R; i++) {
for (int j = 0; j < C; j++) {
// if A[i][j] is 1 then
// add A[i -1][j]
if (A[i][j] == 1) {
A[i][j] += A[i - 1][j];
}
}
(int tmp_result, int tmp_left, int tmp_right) = maxHist(C, A[i]);
// Update result if area with current
// row (as last row of rectangle) is more
if (tmp_result > result) {
left = tmp_left;
right = tmp_right;
bottom = i;
result = tmp_result;
top = bottom - (result / (right - left + 1)) + 1;
}
}
return (result, top, bottom, left, right);
}
// Driver code
public static void Main(string[] args)
{
int R = 4;
int C = 4;
int[][] A = new int[][] {
new int[] { 0, 1, 1, 0 },
new int[] { 1, 1, 1, 1 },
new int[] { 1, 1, 1, 1 },
new int[] { 1, 1, 0, 0 }
};
var result = maxRectangle(R, C, A);
Console.Write("Area of maximum rectangle is " + result.area +
", rows " + result.top + "-" + result.bottom +
", columns " + result.left + "-" + result.right);
}
}
目前,我正在使用这个解决方案:
https://www.geeksforgeeks.org/maximum-sum-rectangle-in-a-2d-matrix-dp-27/
我将 true 转换为 1 & false 转换为 -infinity,然后找到最大和矩形。根据文章,这个解决方案是 O(n^3),而且它确实不够快,无法满足我的需要。我曾尝试使用最大直方图方法 (https://www.youtube.com/watch?v=g8bSdXCG-lA),但矩形大小的存储方式让我在查找最终坐标时遇到了一些麻烦。
C# 中的代码很棒,但如果需要,我很乐意采用伪代码并自己编写。
基于the link provided by the OP:
// C# program to find largest rectangle
// with all 1s in a binary matrix
using System;
using System.Collections.Generic;
class GFG {
// Finds the maximum area under the
// histogram represented by histogram.
// See below article for details.
// https:// www.geeksforgeeks.org/largest-rectangle-under-histogram/
public static (int area, int left, int right) maxHist(int C, int[] row)
{
// Create an empty stack. The stack
// holds indexes of hist[] array.
// The bars stored in stack are always
// in increasing order of their heights.
Stack<int> result = new Stack<int>();
int top_val; // Top of stack
int left;
int max_area = 0; // Initialize max area in current row (or histogram)
int max_left = -1;
int max_right = -1;
int area = 0; // Initialize area with current top
// Run through all bars of
// given histogram (or row)
int i = 0;
while (i < C) {
// If this bar is higher than the
// bar on top stack, push it to stack
if (result.Count == 0 || row[result.Peek()] <= row[i]) {
result.Push(i++);
}
else {
// If this bar is lower than top
// of stack, then calculate area of
// rectangle with stack top as
// the smallest (or minimum height)
// bar. 'i' is 'right index' for
// the top and element before
// top in stack is 'left index'
left = result.Peek();
top_val = row[left];
result.Pop();
area = top_val * i;
if (result.Count > 0) {
left = result.Peek() + 1;
area = top_val * (i - left);
}
if (area > max_area) {
max_area = area;
max_left = left;
max_right = i - 1;
}
}
}
// Now pop the remaining bars from
// stack and calculate area with
// every popped bar as the smallest bar
while (result.Count > 0) {
left = result.Peek();
top_val = row[left];
result.Pop();
area = top_val * i;
if (result.Count > 0) {
left = result.Peek() + 1;
area = top_val * (i - left);
}
if (area > max_area) {
max_area = area;
max_left = left;
max_right = C - 1;
}
}
return (max_area, max_left, max_right);
}
// Returns area of the largest
// rectangle with all 1s in A[][]
public static (int area, int top, int bottom, int left, int right)
maxRectangle(int R, int C, int[][] A)
{
int top = 0;
int bottom = 0;
// Calculate area for first row
// and initialize it as result
(int result, int left, int right) = maxHist(C, A[0]);
// iterate over row to find
// maximum rectangular area
// considering each row as histogram
for (int i = 1; i < R; i++) {
for (int j = 0; j < C; j++) {
// if A[i][j] is 1 then
// add A[i -1][j]
if (A[i][j] == 1) {
A[i][j] += A[i - 1][j];
}
}
(int tmp_result, int tmp_left, int tmp_right) = maxHist(C, A[i]);
// Update result if area with current
// row (as last row of rectangle) is more
if (tmp_result > result) {
left = tmp_left;
right = tmp_right;
bottom = i;
result = tmp_result;
top = bottom - (result / (right - left + 1)) + 1;
}
}
return (result, top, bottom, left, right);
}
// Driver code
public static void Main(string[] args)
{
int R = 4;
int C = 4;
int[][] A = new int[][] {
new int[] { 0, 1, 1, 0 },
new int[] { 1, 1, 1, 1 },
new int[] { 1, 1, 1, 1 },
new int[] { 1, 1, 0, 0 }
};
var result = maxRectangle(R, C, A);
Console.Write("Area of maximum rectangle is " + result.area +
", rows " + result.top + "-" + result.bottom +
", columns " + result.left + "-" + result.right);
}
}