3 reference approaches in C, from brute force to the one to reach for. Compare them with yours.
Read the width with strlen(grid[0]) (every row is the same length) after returning 0 for an empty map, then calloc one bool per cell as the visited array, so the caller's strings are never written. The scan counts each unvisited land cell and calls the static helper sink, which stops at the edges, at water and at visited cells, marks the cell and recurses into its four sides. The flags are freed before returning.
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
static void sink(char** grid, bool* seen, int rows, int cols, int r, int c) {
if (r < 0 || r >= rows || c < 0 || c >= cols) return;
if (grid[r][c] != '1' || seen[r * cols + c]) return;
seen[r * cols + c] = true; // visited
sink(grid, seen, rows, cols, r + 1, c);
sink(grid, seen, rows, cols, r - 1, c);
sink(grid, seen, rows, cols, r, c + 1);
sink(grid, seen, rows, cols, r, c - 1);
}
int numIslands(char** grid, int gridSize) {
if (gridSize == 0) return 0;
int rows = gridSize;
int cols = (int)strlen(grid[0]); // every row has the same length
bool* seen = calloc((size_t)rows * cols + 1, sizeof *seen);
int count = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == '1' && !seen[r * cols + c]) {
count++;
sink(grid, seen, rows, cols, r, c);
}
}
}
free(seen);
return count;
}
Two malloc'ed int arrays, parent and size, hold a disjoint-set forest over the cell numbers r * cols + c. Each land cell adds one island, then tries to merge with the land above and to its left; unite returns true only when two different roots join, and each such merge takes one off the count. find is a loop with path halving and the smaller tree goes under the larger, so the grid is only read and nothing recurses. Both arrays are freed at the end.
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
static int find(int* parent, int x) {
while (parent[x] != x) {
parent[x] = parent[parent[x]]; // path halving
x = parent[x];
}
return x;
}
static bool unite(int* parent, int* size, int a, int b) {
int ra = find(parent, a);
int rb = find(parent, b);
if (ra == rb) return false;
if (size[ra] < size[rb]) {
int t = ra;
ra = rb;
rb = t;
}
parent[rb] = ra; // the smaller tree goes under the larger root
size[ra] += size[rb];
return true;
}
int numIslands(char** grid, int gridSize) {
if (gridSize == 0) return 0;
int rows = gridSize;
int cols = (int)strlen(grid[0]);
int n = rows * cols;
int* parent = malloc(((size_t)n + 1) * sizeof *parent);
int* size = malloc(((size_t)n + 1) * sizeof *size);
for (int i = 0; i < n; i++) {
parent[i] = i;
size[i] = 1;
}
int count = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] != '1') continue;
count++; // a new island until a merge says otherwise
int cell = r * cols + c;
if (r > 0 && grid[r - 1][c] == '1' && unite(parent, size, cell, cell - cols)) count--;
if (c > 0 && grid[r][c - 1] == '1' && unite(parent, size, cell, cell - 1)) count--;
}
}
free(parent);
free(size);
return count;
}
Replace the recursion with a queue: one malloc'ed int array of rows * cols cell indices, read from a head and written at a tail. A cell is marked in the visited array when it is enqueued, so each cell enters the queue at most once and the array can never overflow. Every island reuses the same buffer, starting again at index 0, and the index splits back into row and column with / and %. Both buffers are freed before returning.
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
int numIslands(char** grid, int gridSize) {
if (gridSize == 0) return 0;
int rows = gridSize;
int cols = (int)strlen(grid[0]);
int n = rows * cols;
bool* seen = calloc((size_t)n + 1, sizeof *seen);
int* queue = malloc(((size_t)n + 1) * sizeof *queue); // cell indices r * cols + c
static const int dr[] = {1, -1, 0, 0};
static const int dc[] = {0, 0, 1, -1};
int count = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] != '1' || seen[r * cols + c]) continue;
count++;
int head = 0, tail = 0;
seen[r * cols + c] = true; // mark on enqueue
queue[tail++] = r * cols + c;
while (head < tail) {
int cell = queue[head++];
int cr = cell / cols, cc = cell % cols;
for (int k = 0; k < 4; k++) {
int nr = cr + dr[k], nc = cc + dc[k];
if (nr < 0 || nr >= rows || nc < 0 || nc >= cols) continue;
int next = nr * cols + nc;
if (grid[nr][nc] == '1' && !seen[next]) {
seen[next] = true;
queue[tail++] = next;
}
}
}
}
}
free(seen);
free(queue);
return count;
}