Number of Islands Problem in Python

In this problem, we will be given a 2-dimensional matrix containing only 1s and 0s. In this binary matrix, 0 is considered as water, and 1 is considered as island. An island is considered a group 1, which is surrounded by water in all 4 directions. An island can be made by the 1s connected through 4 directions (note, diagonal 1s will not be considered in the same group).

In this problem, we will be given a 2-dimensional matrix containing only 1s and 0s. In this binary matrix, 0 is considered as water, and 1 is considered as island. An island is considered a group 1, which is surrounded by water in all 4 directions. An island can be made by the 1s connected through 4 directions (note, diagonal 1s will not be considered in the same group).

And the whole matrix is assumed to be surrounded by water.

Let us understand this using an example:

Input: matrix =

[[1, 1, 1, 0, 0],

1, 1, 0, 1, 1],

[1, 0, 0, 1, 0],

[0, 1, 0, 0, 0]]

Output: 3

In this 2D matrix, there are 3 groups of 1s. The first group is on the top left column from rows 0 to 2 and from columns 0 to 2. The second group is from rows 1 to 2 and from columns 3 to 4. The third group is an isolated 1 at the index (2, 2). Note the last element cannot be considered in Group 1 as it is only diagonally connected to the element of Group 1.

We will solve this problem using the concept of connected components of the graph data structure. To solve the problem, first, we need to understand what are connected components in a graph. A graph is a data structure in which there are a certain number of vertices connected through a certain number of edges. However, a graph can be divided into several components and still be considered a single graph. This happens when any node of a cluster in the graph is not connected to any of the nodes of the other cluster. Below is an example of the connected components of the graph

In the above example, there are two components of a single graph.

A graph in which all the vertices are connected, and we can reach all the vertices in a single traversal, is said to have a single component. This type of graph is called a Strongly Connected Graph. However, if we require more than one traversal iteration to reach all the vertices of a graph, then the graph is said to have multiple components.

The graph can be traversed using a Depth First Search and Breadth First Search algorithm. We will solve this problem using both types of traversals.

The main idea to solve the problem is to define two functions, one for the traversal and the other to count the number of traversals made. In the second function, we will create a matrix of the size of the given matrix, and in place of all the elements put False. Now, we will run a nested for loop over each element of the array, and every time we encounter an element that is 1 in the given matrix and marked False in the visited array, in short, the un-visited element, we will call the traversal function. In this loop, we have to count the number of times the traversal function was called. In the traversal function, each visited cell of the matrix will be marked True in its corresponding index in the visited matrix. The number of times the traversal function is called will be our solution. This number represents the number of un-connected components or the number of islands in this problem.

Approach - 1

In this approach, we will use the DFS traversal to traverse the matrix. The idea is the same as explained above. We will create a matrix to track the visited vertices.

Let us see the algorithm of this problem:

  • The first step is to initialize a matrix visited[] of the same size as that of the given matrix. Every element of this visited[] matrix will be set to False.
  • Then, we will initialize the count of the islands, count = 0.
  • Now, we will start a for loop that will traverse all the rows of the matrix; inside this loop, there will be another loop to traverse all the columns of the matrix.
    • Inside the inner loop, we will check if the current element is 1 in the given matrix and marked as False in the visited[] matrix.
    • If yes, then we will increment the count by 1.
    • Also, we will call the traversal function and pass the current element in place of the source element of the function.
    • The DFS traversal function will first mark the source element as True in the visited[] matrix.
    • Then, we will run a loop over the adjacent element of the current source element. The adjacent elements are the elements present in the 4 sides of the source element. To organize the code, we will create two arrays, row = [-1, 0, 0, 1] and column = [0, -1, 1, 0]. These will take care that the function is called for all the adjacent elements of the source element.
  • Suppose the current adjacent element is valid, i.e., in the bounds of the matrix, and the element is marked as 1 in the given matrix. In that case, we will call the DFS function recursively for the adjacent element.
  • When all the traversals are over, we will return the count of the islands, i.e., count.

Below is the Python code for this approach using DFS traversal.

Code

Output

The number of islands in the given matrix is:
3

Time complexity: We are visiting each cell of the matrix in the function countIslands(). Hence, the time complexity is non-linear, i.e., O(r x c), where r is the total number of rows in the given matrix and c is the number of columns.

Auxiliary Space: We have created a matrix to store the visited cells; therefore, the space3 complexity is O(r x c).

The above problem can be modified so that diagonal elements contribute to an island. In that case, we need to call the recursive DFS traversal function on the diagonal elements, too, if that diagonal element is valid. We will include the indices in the row[] and column[] matrices of the DFs traversal so that instead of 4, 8 indices will be checked for each particular element.

Below is the code for the updated problem.

Code

Output

The number of islands in the given matrix is:
3

Space Optimization

In the above algorithm, we have created a different matrix to store the visited nodes. We can optimize the space complexity by solving this problem in place so that we don't need extra O(r * c) space.

Below is the space-optimized code.

Code

Output

The number of islands in the given matrix is:
3

Approach - 2

In this approach, we will use the BFS algorithm. The neighbors are considered the non-diagonal elements of a cell. Therefore, in total, there are 4 neighbors. Hence, in this problem, we will not use the BFS algorithm for all the adjacent cells; instead, we will use the BFS for 4 adjacent cells. We will track the visited cells so that we will not visit them again.

Below is the algorithmic approach to this problem

  • We will initialize a 2D matrix of the same size as the given matrix. We will set all the values of this matrix as False. This matrix will track the visited cells.
  • Now, we will traverse the given matrix, and for each cell that is not visited and is marked as an island in the given matrix, we will perform the BFS traversal function.
  • In the BFS traversal function, we will create a queue data structure and give it the source node. Also, we will mark the source node as visited in the visited matrix.
  • Then, we will start a while loop until the queue is empty.
    • In the loop, we will dequeue the node of the queue; then, we will add the valid adjacent nodes of this node to the queue and mark these adjacent nodes that are islands in the given matrix as visited.
  • After the BFS is complete for the current source code, we will increment the island count by 1.
  • The BFS will be called for each valid unvisited cell.
  • At last, we will return the total island count.

Code

Output

Number of islands in the given matrix is: 5

Time Complexity: O(ROW * COL) where ROW is the number of ROWS and COL is the number of COLUMNS in the matrix.

Auxiliary Space: O(ROW * COL ) because of the visited array.