I got asked at an interview to write a program that, given a NxM matrix with zeros and ones, prints out the list of clusters of 1s. The clusters are defined as patches of 1s connected horizontally, vertically or diagonally.
Here's the code I submitted but I'm wondering if there is a better way, e.g. a well-known algorithm to produce the solution.
namespace ConsoleApplication1
{
/// <summary>
/// Usage:
/// <![CDATA[
///
/// var m = 4; // rows
/// var n = 5; // cols
/// var matrix = new[]
/// {
/// 0,1,0,0,0, // 0-4
/// 0,0,1,1,0, // 5-9
/// 0,0,0,0,0, // 10-14
/// 0,1,1,0,0 // 15-19
/// };
///
/// var finder = new MatrixClusterFinder(matrix, m, n);
/// finder.PrintClusters();
/// PRINTS:
/// (0,1)(1,2)(1,3)
/// (3,1)(3,2)
///
/// ]]>
///
///
///
/// </summary>
public class MatrixClusterFinder
{
private int m;
private int n;
private int[] matrix;
public MatrixClusterFinder(int[] matrix, int m, int n)
{
this.m = m;
this.n = n;
this.matrix = matrix;
}
public void PrintClusters()
{
var visited = new bool[m * n];
for (var i = 0; i < m * n; i++)
{
var isClusterFound = Traverse(i, visited);
if (isClusterFound)
{
Console.WriteLine(); //crlf
}
}
}
private bool Traverse(int curr, bool[] visited)
{
if (visited[curr])
{
return false;
}
bool result = false;
visited[curr] = true;
if (matrix[curr] == 1)
{
result = true;
var thisM = curr / n;
var thisN = curr % n;
Console.Write("({0},{1})", thisM, thisN);
var adjs = GetAdjacent(curr);
foreach (var adj in adjs)
{
Traverse(adj, visited);
}
}
return result;
}
private int[] GetAdjacent(int curr)
{
var thisM = curr / n;
var thisN = curr % n;
var result = new List<int>();
for (var i = thisM; i <= thisM + 1; i++)
{
if (i < 0 || i > m - 1)
{
continue;
}
for (var j = thisN - 1; j <= thisN + 1; j++)
{
if (j < 0 || j > n - 1 || (i == thisM && j < thisN))
{
continue;
}
var res = i * n + j;
if (res == curr)
{
continue;
}
result.Add(res);
}
}
return result.ToArray();
}
}
}