Number of Islands in JavaScript (Time Complexity: O(M*N))


Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

Example 1:

Input:
1 1 1 1 0
1 1 0 1 0
1 1 0 0 0
0 0 0 0 0

Output: 1

Example 2:

Input:
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1

Output: 3

Understanding the Problem

The core challenge of this problem is to identify and count distinct islands in a 2D grid. An island is defined as a group of horizontally or vertically connected '1's (land) surrounded by '0's (water). This problem is significant in various applications such as geographical mapping, image processing, and network connectivity.

Potential pitfalls include not correctly identifying connected components or missing edge cases where islands are at the boundaries of the grid.

Approach

To solve this problem, we can use Depth-First Search (DFS) or Breadth-First Search (BFS) to traverse the grid and mark visited lands. Here’s a step-by-step approach:

Naive Solution

A naive solution would involve checking each cell and performing a search for connected lands. However, this approach can be inefficient due to repeated searches.

Optimized Solution

An optimized solution involves using DFS or BFS to traverse and mark all connected lands starting from each unvisited land cell. This ensures each cell is processed only once.

DFS Approach

1. Iterate through each cell in the grid. 2. When a '1' is found, initiate a DFS to mark all connected '1's. 3. Increment the island count for each DFS initiation.

Algorithm

Here’s a detailed breakdown of the DFS algorithm:

  1. Initialize a counter for the number of islands.
  2. Iterate through each cell in the grid.
  3. If a cell contains '1', initiate a DFS to mark all connected '1's as visited.
  4. Increment the island counter for each DFS initiation.
  5. Return the island counter.

Code Implementation

/**
 * @param {character[][]} grid
 * @return {number}
 */
var numIslands = function(grid) {
    if (!grid || grid.length === 0) return 0;

    let numIslands = 0;

    // Helper function to perform DFS
    const dfs = (grid, i, j) => {
        // Check for out of bounds or water
        if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] === '0') {
            return;
        }

        // Mark the cell as visited by setting it to '0'
        grid[i][j] = '0';

        // Perform DFS in all four directions
        dfs(grid, i + 1, j); // down
        dfs(grid, i - 1, j); // up
        dfs(grid, i, j + 1); // right
        dfs(grid, i, j - 1); // left
    };

    // Iterate through each cell in the grid
    for (let i = 0; i < grid.length; i++) {
        for (let j = 0; j < grid[0].length; j++) {
            if (grid[i][j] === '1') {
                numIslands++;
                dfs(grid, i, j);
            }
        }
    }

    return numIslands;
};

Complexity Analysis

The time complexity of this approach is O(M*N), where M is the number of rows and N is the number of columns. This is because each cell is visited once. The space complexity is O(M*N) in the worst case due to the recursion stack in DFS.

Edge Cases

Potential edge cases include:

Testing these edge cases ensures the robustness of the solution.

Testing

To test the solution comprehensively, consider the following test cases:

Using a testing framework like Jest can help automate and validate these test cases.

Thinking and Problem-Solving Tips

When approaching such problems, consider the following tips:

Conclusion

Understanding and solving the "Number of Islands" problem is crucial for mastering grid-based traversal algorithms. By practicing and exploring different approaches, you can enhance your problem-solving skills and prepare for more complex challenges.

Additional Resources

For further reading and practice, consider the following resources: