200. Number of Islands

Union-Find

In this solution, we use Weighted Quick-Union to count the number of connected domain, which is an implementation of Union-Find algorithm in Robert Sedgewick and Kevin Wayne’s Algorithm.

Note that we should minus the number of ‘0’ islands, cause the algorithm also considers them as independent connected domains.

class Solution {
    public int numIslands(char[][] grid) {
        if (grid.length == 0 || grid[0].length == 0) {
            return 0;
        }
        int row = grid.length;
        int column = grid[0].length;
        UnionFind uf = new UnionFind(row * column);
        int zeroCounter = 0;
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                if (grid[i][j] == '0') {
                    zeroCounter++;
                    continue;
                }
                int curr = i * column + j;
                int target;
                if (i > 0 && grid[i - 1][j] == '1') {
                    target = curr - column;
                    uf.union(curr, target);
                }
                if (i < row - 1 && grid[i + 1][j] == '1') {
                    target = curr + column;
                    uf.union(curr, target);
                }
                if (j > 0 && grid[i][j - 1] == '1') {
                    target = curr - 1;
                    uf.union(curr, target);
                }
                if (j < column - 1 && grid[i][j + 1] == '1') {
                    target = curr + 1;
                    uf.union(curr, target);
                }
            }
        }
        // remove '0' counting
        return uf.count() - zeroCounter;
    }

    private static class UnionFind {
        private int[] id;
        private int[] sz;
        private int count;

        public UnionFind(int n) {
            this.id = new int[n];
            this.sz = new int[n];
            for (int i = 0; i < n; i++) {
                id[i] = i;
                sz[i] = 1;
            }
            this.count = n;
        }

        public void union(int p, int q) {
            int i = find(p);
            int j = find(q);
            if (i == j) {
                return;
            }
            // link small tree to large tree
            if (sz[i] < sz[j]) {
                id[i] = j;
                sz[j] += sz[i];
            } else {
                id[j] = i;
                sz[i] += sz[j];
            }
            count--;
        }

        // find the root of p
        public int find(int p) {
            while (p != id[p]) {
                p = id[p];
            }
            return p;
        }

        public boolean connected(int p, int q) {
            return find(p) == find(q);
        }

        public int count() {
            return count;
        }
    }
}

DFS

class Solution {
    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 islands = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == '1') {
                    // for all UNVISITED land, do a dfs
                    dfs(i, j, grid);
                    islands++;
                }
            }
        }
        return islands;
    }

    private void dfs(int i, int j, char[][] grid) {
        // if (i, j) is out of bounds or (i, j) is not a land, return
        if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] != '1') {
            return;
        }
        // mark as visited
        grid[i][j] = '0';
        dfs(i - 1, j, grid);
        dfs(i + 1, j, grid);
        dfs(i, j - 1, grid);
        dfs(i, j + 1, grid);
    }
}