Java Program to Find Number of Islands
dfs(), then count how many times you start a new DFS on unvisited land cells.Examples
How to Think About It
Algorithm
Code
public class NumberOfIslands { public static int numIslands(int[][] grid) { int count = 0; boolean[][] visited = new boolean[grid.length][grid[0].length]; for (int i = 0; i < grid.length; i++) { for (int j = 0; j < grid[0].length; j++) { if (grid[i][j] == 1 && !visited[i][j]) { dfs(grid, visited, i, j); count++; } } } return count; } private static void dfs(int[][] grid, boolean[][] visited, int i, int j) { if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == 0 || visited[i][j]) { return; } visited[i][j] = true; dfs(grid, visited, i + 1, j); dfs(grid, visited, i - 1, j); dfs(grid, visited, i, j + 1); dfs(grid, visited, i, j - 1); } public static void main(String[] args) { int[][] grid = { {1, 1, 0, 0, 0}, {1, 1, 0, 0, 0}, {0, 0, 1, 0, 0}, {0, 0, 0, 1, 1} }; System.out.println(numIslands(grid)); } }
Dry Run
Let's trace the example grid [[1,1,0,0,0],[1,1,0,0,0],[0,0,1,0,0],[0,0,0,1,1]] through the code
Start scanning grid
At cell (0,0), value is 1 and not visited, start DFS and increment count to 1.
DFS marks connected land
Mark (0,0), (0,1), (1,0), (1,1) as visited.
Continue scanning
Cells (0,2) to (1,4) are water or visited, skip.
Find next island
At cell (2,2), value is 1 and not visited, start DFS and increment count to 2.
Mark single cell island
Mark (2,2) visited.
Find last island
At cell (3,3), value is 1 and not visited, start DFS and increment count to 3.
Mark connected land
Mark (3,3) and (3,4) visited.
| Step | Island Count | Visited Cells |
|---|---|---|
| 1 | 1 | (0,0),(0,1),(1,0),(1,1) |
| 2 | 2 | (2,2) |
| 3 | 3 | (3,3),(3,4) |
Why This Works
Step 1: Scan each cell
We check every cell to find unvisited land cells which indicate a new island.
Step 2: Use DFS to mark connected land
DFS visits all connected land cells (up, down, left, right) marking them visited to avoid recounting.
Step 3: Count islands
Each time DFS starts on a new unvisited land cell, it means a new island is found, so we increase the count.
Alternative Approaches
import java.util.LinkedList; import java.util.Queue; public class NumberOfIslandsBFS { public static int numIslands(int[][] grid) { int count = 0; boolean[][] visited = new boolean[grid.length][grid[0].length]; int[] dx = {1, -1, 0, 0}; int[] dy = {0, 0, 1, -1}; for (int i = 0; i < grid.length; i++) { for (int j = 0; j < grid[0].length; j++) { if (grid[i][j] == 1 && !visited[i][j]) { count++; Queue<int[]> queue = new LinkedList<>(); queue.add(new int[]{i, j}); visited[i][j] = true; while (!queue.isEmpty()) { int[] cell = queue.poll(); for (int k = 0; k < 4; k++) { int x = cell[0] + dx[k]; int y = cell[1] + dy[k]; if (x >= 0 && y >= 0 && x < grid.length && y < grid[0].length && grid[x][y] == 1 && !visited[x][y]) { queue.add(new int[]{x, y}); visited[x][y] = true; } } } } } } return count; } public static void main(String[] args) { int[][] grid = { {1, 1, 0, 0, 0}, {1, 1, 0, 0, 0}, {0, 0, 1, 0, 0}, {0, 0, 0, 1, 1} }; System.out.println(numIslands(grid)); } }
public class NumberOfIslandsUnionFind { private int[] parent; private int count; public NumberOfIslandsUnionFind(int[][] grid) { int m = grid.length, n = grid[0].length; parent = new int[m * n]; count = 0; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (grid[i][j] == 1) { int id = i * n + j; parent[id] = id; count++; } else { parent[i * n + j] = -1; } } } } public int find(int i) { if (parent[i] != i) { parent[i] = find(parent[i]); } return parent[i]; } public void union(int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX != rootY) { parent[rootX] = rootY; count--; } } public int getCount() { return count; } public static int numIslands(int[][] grid) { int m = grid.length, n = grid[0].length; NumberOfIslandsUnionFind uf = new NumberOfIslandsUnionFind(grid); int[] dx = {1, 0}; int[] dy = {0, 1}; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (grid[i][j] == 1) { for (int k = 0; k < 2; k++) { int x = i + dx[k]; int y = j + dy[k]; if (x < m && y < n && grid[x][y] == 1) { uf.union(i * n + j, x * n + y); } } } } } return uf.getCount(); } public static void main(String[] args) { int[][] grid = { {1, 1, 0, 0, 0}, {1, 1, 0, 0, 0}, {0, 0, 1, 0, 0}, {0, 0, 0, 1, 1} }; System.out.println(numIslands(grid)); } }
Complexity: O(m*n) time, O(m*n) space
Time Complexity
We visit each cell once, and DFS explores connected cells, so total time is proportional to grid size O(m*n).
Space Complexity
We use a visited array of size m*n and recursion stack in worst case can be O(m*n).
Which Approach is Fastest?
DFS and BFS have similar time and space complexity; Union-Find can be faster for multiple queries but is more complex.
| Approach | Time | Space | Best For |
|---|---|---|---|
| DFS | O(m*n) | O(m*n) | Simple and intuitive for single grid |
| BFS | O(m*n) | O(m*n) | Iterative alternative to DFS |
| Union-Find | O(m*n) | O(m*n) | Efficient for dynamic connectivity or multiple queries |