给定一个大小为mxn
的矩阵,仅包含0和1。我需要找到最大的子矩阵,其中包含相同数量的1和0。蛮力方法是O(m^2*n^2)
我们可以做得比这更好吗?
我尝试应用动态编程,但找不到任何最佳子结构。
我相信这个问题的类似的一维版本在这里讨论:
Space-efficient algorithm for finding the largest balanced subarray?
它有O(n)
解决方案,使用一些额外的空间。
答案 0 :(得分:5)
该算法假设我们搜索具有连续行和列的子矩阵,并且具有最大可能的高度和宽度乘积。
从以下预处理开始:
A = substitute_zero_with_minus_one(InputMatrix)
B = prefix_sum_for_each_column(A)
C = prefix_sum_for_each_row(B)
现在,对于每对行(i,j),请执行以下操作:
for each column k:
d = C[k, j] - C[k, i]
if h[d] not empty:
if (k - h[d]) * (j - i) is greater than best result:
update best result
else:
h[d] = k
时间复杂度为O(N 2 * M),额外空间为O(N * M)。
答案 1 :(得分:1)
我们假设m< n,我们可以有一个O(M * M * N)算法。 如果我们将所有0替换为-1,我们只需找到最大的子矩阵,其总和为0.
答案 2 :(得分:1)
我假设只使用连续的行\列形成子矩阵 原始矩阵(即通过删除第一个\最后一行或列)。
这样,矩阵可以表示为
Mat = {origin(row,col), rowCount, columnCount}
如果原始矩阵的维数为M x N,那么
rowCount = M - row
columnCount = N - col
Mat = {origin(row,col), M - row, N - col}.
变量row
和col
分别有M
和N
个值,这意味着
有O(MxN)
个这样的矩阵。
算法理念
(m, n)
(m, n-1)
和(m-1, n)
并放入队列现在有两点:
O(n)
或O(m)
时间。这是动态编程步骤。这意味着复杂性为O(max(M,N)MN)
答案 3 :(得分:1)
我创建了一个演示搜索算法优化的小应用程序。如果您正在寻找,请告诉我。
注意:
这是:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Program
{
class Matrix
{
public int[][] JaggedInteger2DMatrix { get; set; }
public List<MatrixCell> Cells { get; set; }
public List<MatrixLine> Lines { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public Matrix(int size, int seed)
{
var r = new Random(seed);
int[][] jaggedInteger2DMatrix = new int[size][];
for (int i = 0; i < size; i++)
{
jaggedInteger2DMatrix[i] = new int[size];
for (int j = 0; j < size; j++)
{
jaggedInteger2DMatrix[i][j] = r.Next(2);
//Console.Write(jaggedInteger2DMatrix[i][j]+" ");
}
//Console.Write("\r\n");
}
InitializeMatrix(jaggedInteger2DMatrix);
}
public Matrix(int[][] jaggedInteger2DMatrix)
{
InitializeMatrix(jaggedInteger2DMatrix);
}
private void InitializeMatrix(int[][] jaggedInteger2DMatrix)
{
JaggedInteger2DMatrix = jaggedInteger2DMatrix;
Height = jaggedInteger2DMatrix.GetLength(0);
Width = jaggedInteger2DMatrix[0].GetLength(0);
Cells = new List<MatrixCell>();
Lines = new List<MatrixLine>();
int horizontalLineCounter = 0;
MatrixCell matrixCell = null;
foreach (var horizontalLine in jaggedInteger2DMatrix)
{
int verticalLineCounter = 0;
foreach (var cell in horizontalLine)
{
matrixCell = new MatrixCell()
{
HorizontalLineIndex = horizontalLineCounter,
Value = cell,
VerticalLineIndex = verticalLineCounter
};
Cells.Add(matrixCell);
if (Lines.Where(line => line.LineType == Line.Vertical && line.LineIndex == verticalLineCounter).Count() == 0)
{
var line = new MatrixLine()
{
LineType = Line.Vertical,
LineIndex = verticalLineCounter
};
Lines.Add(line);
}
Lines.Where(line => line.LineType == Line.Vertical && line.LineIndex == verticalLineCounter).FirstOrDefault().Cells.Add(matrixCell);
if (Lines.Where(line => line.LineType == Line.Horizontal && line.LineIndex == horizontalLineCounter).Count() == 0)
{
var line = new MatrixLine()
{
LineType = Line.Horizontal,
LineIndex = horizontalLineCounter
};
Lines.Add(line);
}
Lines.Where(line => line.LineType == Line.Horizontal && line.LineIndex == horizontalLineCounter).FirstOrDefault().Cells.Add(matrixCell);
verticalLineCounter++;
}
horizontalLineCounter++;
}
}
}
class MatrixCell
{
public int Value { get; set; }
public int VerticalLineIndex { get; set; }
public int HorizontalLineIndex { get; set; }
}
class MatrixLine
{
public Line LineType { get; set; }
public int LineIndex { get; set; }
public List<MatrixCell> Cells { get; set; }
public MatrixLine()
{
Cells = new List<MatrixCell>();
}
}
enum Line
{
Horizontal,
Vertical
}
private static void Search(Matrix matrix, bool optimizeCellCount, out IEnumerable<MatrixCell> optimizedSelection, out int iterations)
{
optimizedSelection = null;
var count = 0;
iterations = 0;
for (int i = 0; i < matrix.Width; i++)
{
for (int j = 1; j <= matrix.Width; j++)
{
var selectedVerticalLines = matrix.Lines.Where(line => line.LineType == Line.Vertical).Skip(i).Take(j);
for (int k = 0; k < matrix.Height; k++)
{
for (int l = 1; l <= matrix.Height; l++)
{
/**
* Here's where the search is optimized
**********************************************************************************************
*/
if (optimizeCellCount)
{
//if the submatrix cell count is smaller than the current count, break the iteration
if (count > Math.Min(Math.Abs(matrix.Height - k), l) * Math.Min(Math.Abs(matrix.Height - i), j))
{
continue;
}
}
/*
**********************************************************************************************
*/
iterations++;
var selectedHorizontalLines = matrix.Lines.Where(line => line.LineType == Line.Horizontal).Skip(k).Take(l);
var horizontalCells = selectedHorizontalLines.Aggregate<MatrixLine, List<MatrixCell>>(new List<MatrixCell>(), (a, b) =>
{
a.AddRange(b.Cells);
return a;
});
var verticalCells = selectedVerticalLines.Aggregate<MatrixLine, List<MatrixCell>>(new List<MatrixCell>(), (a, b) =>
{
a.AddRange(b.Cells);
return a;
});
var cells = horizontalCells.Intersect(verticalCells);
if (cells.Count() > count)
{
var sum = cells.Sum(t => t.Value);
var cellsCount = cells.Count();
if (sum != 0)
{
if (cellsCount / (double)sum == 2)
{
//match
optimizedSelection = cells;
count = cellsCount;
}
}
}
}
}
}
}
}
private static float GetLineCost(int width, int startPosition, int length)
{
float cost = 0;
for (int i = startPosition; i < length; i++)
{
cost += Math.Min(Math.Abs(width - i), i + 1);
}
return cost;
}
static void Main(string[] args)
{
Matrix matrix = new Matrix(20, 1);
bool optimizeCellCount = true;
IEnumerable<MatrixCell> optimizedSelection;
int iterations;
var watch = new System.Diagnostics.Stopwatch();
//optimized search
watch.Start();
Search(matrix, optimizeCellCount, out optimizedSelection, out iterations);
watch.Stop();
Console.WriteLine("Full Optimized Search");
Console.WriteLine("position: [{0},{1}],[{2},{3}] size : {4} search time : {5} iterations: {6}",
optimizedSelection.Min(cell => cell.VerticalLineIndex),
optimizedSelection.Min(cell => cell.HorizontalLineIndex),
optimizedSelection.Max(cell => cell.VerticalLineIndex),
optimizedSelection.Max(cell => cell.HorizontalLineIndex),
optimizedSelection.Count(),
watch.Elapsed,
iterations
);
watch.Reset();
//no optimization
watch.Start();
Search(matrix, !optimizeCellCount, out optimizedSelection, out iterations);
watch.Stop();
Console.WriteLine("Non-Optimized Search");
Console.WriteLine("position: [{0},{1}],[{2},{3}] size : {4} search time : {5} iterations: {6}",
optimizedSelection.Min(cell => cell.VerticalLineIndex),
optimizedSelection.Min(cell => cell.HorizontalLineIndex),
optimizedSelection.Max(cell => cell.VerticalLineIndex),
optimizedSelection.Max(cell => cell.HorizontalLineIndex),
optimizedSelection.Count(),
watch.Elapsed,
iterations
);
watch.Reset();
//Console Output:
/***************************************************************************************
* Full Optimized Search
* position: [9,1],[18,19] size : 190 search time : 00:00:02.3963657 iterations: 19108
* Non-Optimized Search
* position: [9,1],[18,19] size : 190 search time : 00:00:05.8385388 iterations: 160000
****************************************************************************************/
}
}