Lesson 143 of 250
200. Number of Islands
NeetCode: Number of Islands · LeetCode: 200. Number of Islands · Difficulty: Medium
Given an m x n grid of '1' (land) and '0' (water), return the number of islands. An island is a maximal group of land cells connected horizontally or vertically.
Example
grid: 11110 Output: 1
11010
11000
00000
grid: 11000 Output: 3
11000
00100
00011A grid is an implicit graph: each cell is a node and its four neighbors are its edges. Counting islands is counting connected components: scan the cells, and each time unvisited land is found, count one island and flood-fill everything connected to it so it is not counted again.
The grid is a char[][]. The examples build it from strings with a helper parse that calls String.toCharArray() on each row.
Brute force: recursive DFS with a visited matrix
Keep the input untouched and record what has been seen in a separate visited matrix. The recursion visits every cell of an island once.
class Solution {
private static final int[][] DIRS = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
private void dfs(char[][] grid, boolean[][] visited, int r, int c) {
visited[r][c] = true;
for (int[] d : DIRS) {
int nr = r + d[0];
int nc = c + d[1];
if (nr < 0 || nc < 0 || nr >= grid.length || nc >= grid[0].length) {
continue;
}
if (grid[nr][nc] == '1' && !visited[nr][nc]) {
dfs(grid, visited, nr, nc);
}
}
}
public int numIslands(char[][] grid) {
if (grid.length == 0 || grid[0].length == 0) {
return 0;
}
boolean[][] visited = new boolean[grid.length][grid[0].length];
int count = 0;
for (int r = 0; r < grid.length; r++) {
for (int c = 0; c < grid[0].length; c++) {
if (grid[r][c] == '1' && !visited[r][c]) {
count++;
dfs(grid, visited, r, c);
}
}
}
return count;
}
}
public class Main {
static char[][] parse(String... rows) {
char[][] grid = new char[rows.length][];
for (int i = 0; i < rows.length; i++) {
grid[i] = rows[i].toCharArray();
}
return grid;
}
public static void main(String[] args) {
Solution s = new Solution();
System.out.println(s.numIslands(parse("11110", "11010", "11000", "00000")));
System.out.println(s.numIslands(parse("11000", "11000", "00100", "00011")));
System.out.println(s.numIslands(parse()));
}
}1
3
0Both versions are linear. The practical costs are that the recursion depth can reach m * n on a snake-shaped island, which throws StackOverflowError on large grids because Java's thread stack is limited, and that the extra matrix doubles the memory. Time: O(m * n). Space: O(m * n) for visited plus the recursion stack.
Optimal: iterative flood fill that sinks land in place
Replace the recursion with an explicit stack (an ArrayDeque on the heap, so the call stack cannot overflow), and instead of a visited matrix overwrite each land cell with '0' when it is pushed. Sunk land is exactly already-seen land. The method modifies the grid it is given, which LeetCode allows.
import java.util.ArrayDeque;
import java.util.Deque;
class Solution {
private static final int[][] DIRS = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
public int numIslands(char[][] grid) {
if (grid.length == 0 || grid[0].length == 0) {
return 0;
}
int m = grid.length;
int n = grid[0].length;
int count = 0;
for (int r = 0; r < m; r++) {
for (int c = 0; c < n; c++) {
if (grid[r][c] != '1') {
continue;
}
count++;
grid[r][c] = '0';
Deque<int[]> stack = new ArrayDeque<>();
stack.push(new int[]{r, c});
while (!stack.isEmpty()) {
int[] cell = stack.pop();
for (int[] d : DIRS) {
int nr = cell[0] + d[0];
int nc = cell[1] + d[1];
if (nr < 0 || nc < 0 || nr >= m || nc >= n) {
continue;
}
if (grid[nr][nc] == '1') {
grid[nr][nc] = '0';
stack.push(new int[]{nr, nc});
}
}
}
}
}
return count;
}
}
public class Main {
static char[][] parse(String... rows) {
char[][] grid = new char[rows.length][];
for (int i = 0; i < rows.length; i++) {
grid[i] = rows[i].toCharArray();
}
return grid;
}
public static void main(String[] args) {
Solution s = new Solution();
System.out.println(s.numIslands(parse("11110", "11010", "11000", "00000")));
System.out.println(s.numIslands(parse("11000", "11000", "00100", "00011")));
System.out.println(s.numIslands(parse()));
}
}1
3
0Marking a cell when it is pushed, not when it is popped, guarantees it is pushed at most once. Time: O(m * n), each cell is sunk once and looked at from four sides. Space: O(m * n) worst case for the stack, with no visited matrix.
