Skip to content

Instantly share code, notes, and snippets.

@BrightSoul
Last active August 19, 2021 10:29
Show Gist options
  • Save BrightSoul/da12c3581ae390521684cee56235e7ce to your computer and use it in GitHub Desktop.
Save BrightSoul/da12c3581ae390521684cee56235e7ce to your computer and use it in GitHub Desktop.
C# solution to AlgoExpert's RemoveIslands problem as seen here: https://www.youtube.com/watch?v=4tYoVx0QoN0
using System;
using System.Collections.Generic;
using System.Drawing;
namespace RemoveIslandsProblem
{
class Program
{
private const int ArraySize = 6;
static void Main(string[] args)
{
bool[,] input = GenerateMatrix();
bool[,] output = RemoveIslands(input);
PrintMatrix(input);
PrintMatrix(output);
}
private static bool[,] RemoveIslands(bool[,] matrix)
{
int xLength = matrix.GetLength(0);
int yLength = matrix.GetLength(1);
bool[,] output = new bool[xLength, yLength];
HashSet<Point> dockedPoints = new HashSet<Point>();
for (int x = 0; x < xLength; x++)
{
for (int y = 0; y < yLength; y++)
{
output[x, y] = IsPointDocked(new Point(x, y), matrix, dockedPoints);
}
}
return output;
}
private static bool IsPointDocked(Point point, bool[,] matrix, HashSet<Point> dockedPoints)
{
// Not interested in points with a false value: it sould stay false
if (!matrix[point.X, point.Y])
{
return false;
}
bool isDocked = false;
int xUpperBound = matrix.GetLength(0) - 1;
int yUpperBound = matrix.GetLength(1) - 1;
// Keep track of points we've visited, they will be added to a cache later
// if we find they're docked to the border either directly or indirectly
HashSet<Point> visitedPoints = new HashSet<Point>();
// Let's keep track of all candidate neighbor points which
// we'll have to evaluate in order to find out if they lead to the border
Queue<Point> candidatePoints = new Queue<Point>();
// Start evaluating the one we're at
candidatePoints.Enqueue(point);
while (candidatePoints.TryDequeue(out Point candidatePoint))
{
visitedPoints.Add(candidatePoint);
// Great, we reached a point that's on border so our search is over
// and x and y coords must be kept
if (IsPointOnBorder(candidatePoint, xUpperBound, yUpperBound))
{
isDocked = true;
break;
}
// Otherwise, go visit neighbors
Point[] neighborPoints = GetNeighborPoints(candidatePoint);
// TODO: Sort neighborPoints so that those closest to known docked points are evaluated first?
// May be counter productive though.
foreach (Point neighborPoint in neighborPoints)
{
// Not interested in neighbor points having a false value
if (!matrix[neighborPoint.X, neighborPoint.Y])
{
continue;
}
// Is this a point we've visited already?
// e.g. we don't want to be stuck in a donut forever
if (visitedPoints.Contains(neighborPoint))
{
continue;
}
// Is this neighbor a point we already know is docked to the border?
// If so, then our current x,y point is also docked
if (dockedPoints.Contains(neighborPoint))
{
isDocked = true;
break;
}
// Enqueue for later evaluation. Maybe one of this
// neighbor's neighbors is docked to the border
// Since this is a queue, it will be a Depth Search First
candidatePoints.Enqueue(neighborPoint);
}
}
if (isDocked)
{
// All the points we've visited are docked to the border
// add them to a cache so we won't need to visit them again
foreach (Point visitedPoint in visitedPoints)
{
dockedPoints.Add(visitedPoint);
}
}
return isDocked;
}
private static Point[] GetNeighborPoints(Point point)
{
// Only adjacent neighbors (no diagonal)
return new Point[]
{
new Point(point.X-1, point.Y),
new Point(point.X+1, point.Y),
new Point(point.X, point.Y-1),
new Point(point.X, point.Y+1)
};
}
private static bool IsPointOnBorder(Point point, int xUpperBound, int yUpperBound)
{
return point.X == 0 || point.Y == 0 || point.X == xUpperBound || point.Y == yUpperBound;
}
private static void PrintMatrix(bool[,] matrix)
{
Console.WriteLine();
for (int x = 0; x < matrix.GetLength(0); x++)
{
Console.WriteLine();
for (int y = 0; y < matrix.GetLength(1); y++)
{
Console.Write(matrix[x, y] ? '▓' : '░');
}
}
}
private static bool[,] GenerateMatrix()
{
bool[,] matrix = new bool[ArraySize, ArraySize];
Random random = new Random();
for (int x = 0; x < matrix.GetLength(0); x++)
{
for (int y = 0; y < matrix.GetLength(1); y++)
{
matrix[x, y] = random.NextDouble() >= 0.7;
}
}
return matrix;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment