Minimum Island (Grid Flood Fill)
Same island scan as `islandCount`, but track size the way `largestComponent` does and reduce with `Math.min` instead of `Math.max`. The only real wrinkle is picking an identity value that plays nice with a minimum: `Infinity`, not `0` — a real island's size can never lose to it, and 'no island found' is the one case that should come back out as `Infinity` too.
The problem
Implement `minimumIsland(graph)` over the same `'W'`/`'L'` grid as `islandCount`, but return the size of the *smallest* land mass instead of how many exist. Land is still connected up/down/left/right, not diagonally.
If the grid has no land at all, the answer is `Infinity` — there's no smallest island to report, and a fallback like `0` would read as a real (if tiny) answer instead of 'there wasn't one'.
The approach
`exploreGraph` keeps the exact same three rejection cases as `islandCount` — out of bounds, water, already visited — but now returns `Infinity` for all of them instead of `false`. A real island still gets BFS'd and returns its actual size, counted the same way `largestComponent` counted a component: a running `size` incremented each time a new cell is marked visited and queued.
The outer loop does `Math.min(minIslandLength, exploreGraph(...))` across every `(r, c)` in the grid, water and revisited land included. Since `Infinity` can never win a `Math.min` against a real number, only genuine islands ever move the answer — the same trick `largestComponent` used with `0` and `Math.max`, just flipped for the opposite reduction.
That symmetry is also what makes the all-water grid correct for free: every single cell returns `Infinity` from `exploreGraph`, so `minIslandLength` never leaves its initial value and the function returns `Infinity` — exactly the sentinel the empty case needs, with no separate check required.
The solution
export function minimumIsland(graph) {
const visited = new Set();
let minIslandLength = Infinity;
for (let r = 0; r < graph.length; r++) {
for (let c = 0; c < graph[0].length; c++) {
minIslandLength = Math.min(minIslandLength, exploreGraph(graph, r, c, visited))
}
}
return minIslandLength;
}
export function exploreGraph(graph, r, c, visited) {
const rowInBound = r >= 0 && r < graph.length;
const colInBound = c >= 0 && c < graph[0].length;
const pos = `${r},${c}`;
if (!rowInBound || !colInBound || graph[r][c] === 'W' || visited.has(pos)) {
return Infinity;
}
const q = [[r, c]];
visited.add(pos);
let size = 1
const directions = [
[1, 0], [-1, 0], [0, 1], [0, -1]
];
while (q.length > 0) {
const [cr, cc] = q.shift();
for (const [dr, dc] of directions) {
const [nr, nc] = [cr + dr, cc + dc];
const inBounds = nr >= 0 && nr < graph.length && nc >= 0 && nc < graph[0].length;
const neighborPos = `${nr},${nc}`;
if (
inBounds &&
graph[nr][nc] === 'L' &&
!visited.has(neighborPos)
) {
visited.add(neighborPos);
q.push([nr, nc]);
size++
}
}
}
return size;
}Time O(R * C)Space O(R * C)