After further thought, I came up with a faster solution:
Create an immutable Range structure with StartX , StartY and EndY properties.
Maintain a sparse array of current Range s, with a length equal to the height of the image, and one variable with a currentRange value of zero. This array will contain a range, if any, that starts with each Y coordinate
For each column
This algorithm is O(x * y) in computing and O(y) in space. I believe this is the quickest solution to the problem.
You can also rotate this algorithm and scan rows, not columns (so that the ranges will be stretched down rather than right), which will be O(x) in the repository.
Here is the C # implementation:
class BoxFinder { class Range { public Range(int startX, int startY, int endY) { StartX = startX; StartY = startY; EndY = endY; } public int StartX { get; private set; } public int StartY { get; private set; } public int EndY { get; private set; } } public BoxFinder(int[,] data) { Data = data; Width = data.GetLength(0); Height = data.GetLength(1); ranges = new Range[Height]; } public int[,] Data { get; private set; } public int Width { get; private set; } public int Height { get; private set; } private Range[] ranges; public IEnumerable<Rectangle> GetBoxes() { for (int x = 0; x < Width; x++) { Range currentRange = null; for (int y = 0; y < Height; y++) { Func<Range, Rectangle> CloseRange = r => { currentRange = null; ranges[r.StartY] = null; return new Rectangle( r.StartY, r.StartX, x - r.StartX, r.EndY - r.StartY ); }; if (currentRange == null || currentRange.EndY <= y) currentRange = ranges[y]; if (Data[x, y] == 1) { if (currentRange == null) { int startY = y; for (; y < Height && Data[x, y] == 1; y++) { if (ranges[y] != null) yield return CloseRange(ranges[y]);
SLaks
source share