Number of Islands

Problem

A grid has 1 for land and 0 for water. An island is a group of land cells connected up, down, left or right. Print the number of islands.

Constraints

  • 1 <= r, c <= 100

Examples

Input

4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1

Output

3

Solutions

Best approachTime O(r * c)Space O(r * c)

We scan the grid. A land cell that is not visited yet starts a new island, and a flood fill marks all its cells. We use an explicit stack instead of recursion, so a big island can not overflow the call stack.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Process a grid.
 * Input   : r and c, then r rows of c numbers (0 or 1).
 * Output  : The number of islands.
 * Approach: Flood fill each island once.
 * Time    : O(r * c)
 * Space   : O(r * c)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
    // This method solves the task. It receives the input and returns the answer.
    static int solve(int[][] m) {
        int rows = m.length;
        int cols = m[0].length;
        boolean[][] visited = new boolean[rows][cols];
        int islands = 0;

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                // Step 1: A land cell that was not visited belongs to a new island.
                if (m[i][j] == 1 && !visited[i][j]) {
                    islands++;

                    // Step 2: Visit the whole island with a stack (depth-first search) and mark every cell.
                    java.util.ArrayDeque<int[]> stack = new java.util.ArrayDeque<>();
                    stack.push(new int[] {i, j});
                    visited[i][j] = true;
                    while (!stack.isEmpty()) {
                        int[] cell = stack.pop();
                        int[][] neighbours = {{cell[0] + 1, cell[1]}, {cell[0] - 1, cell[1]}, {cell[0], cell[1] + 1}, {cell[0], cell[1] - 1}};
                        for (int[] next : neighbours) {
                            if (next[0] >= 0 && next[0] < rows && next[1] >= 0 && next[1] < cols
                                    && m[next[0]][next[1]] == 1 && !visited[next[0]][next[1]]) {
                                visited[next[0]][next[1]] = true;
                                stack.push(next);
                            }
                        }
                    }
                }
            }
        }

        // Step 3: The number of starts is the number of islands.
        return islands;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int rows = scanner.nextInt();
        int cols = scanner.nextInt();
        int[][] m = new int[rows][cols];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                m[i][j] = scanner.nextInt();
            }
        }
        System.out.println(solve(m));
    }
}
Hints (2)
  1. Why do we mark cells as visited?
  2. Why use a stack instead of recursion?