Introduction to Island Pattern
Many coding interview problems involve traversing 2D arrays (aka matrix or grid). The Island pattern describes all the efficient ways to traverse a matrix. This pattern will go through many problems to explain matrix traversal using Depth First Search (DFS) and Breadth First Search (BFS) approaches and their variants.
Let’s jump onto our first problem to develop an understanding of this pattern.
Number of Islands
Top Interview 150 | 200. Number of Islands Design Gurus
Problem Statement
Given a 2D array (i.e., a matrix) containing only 1s (land) and 0s (water), count the number of islands in it.
An island is a connected set of 1s (land) and is surrounded by either an edge or 0s (water). Each cell is considered connected to other cells horizontally or vertically (not diagonally).
Example 1
Input: matrix =
Output: 1
Explanation: The matrix has only one island. See the highlighted cells below.
Example 2
Input: matrix =
Output: 3
Explanation: The matrix has three islands. See the highlighted cells below.
Constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 300
matrix[i][j] is '0' or '1'.
Solution
We can traverse the matrix linearly to find islands.
Whenever we find a cell with the value ‘1’ (i.e., land), we have found an island. Using that cell as the root node, we will perform a Depth First Search (DFS) or Breadth First Search (BFS) to find all of its connected land cells. During our DFS or BFS traversal, we will find and mark all the horizontally and vertically connected land cells.
We need to have a mechanism to mark each land cell to ensure that each land cell is visited only once. To mark a cell visited, we have two options:
- We can update the given input matrix. Whenever we see a ‘1’, we will make it ‘0’.
- A separate boolean matrix can be used to record whether or not each cell has been visited.
Following is the DFS or BFS traversal of the example-2 mentioned above:
By following the above algorithm, every time DFS or BFS is triggered, we are sure that we have found an island. We will keep a running count to calculate the total number of islands.
Below, we will see three solutions based on:
- DFS
- BFS
- BFS with visited matrix
Code (DFS)
Here is what our DFS algorithm will look like. We will update the input matrix to mark cells visited.
1 | # dfs一般使用stack或者递归 |
Time Complexity
Time complexity of the above algorithm will be O(M \ N)*, where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix. This is due to the fact that we have to traverse the whole matrix to find the islands.
Space Complexity
DFS recursion stack can go O(M \ N)* deep when the whole matrix is filled with ‘1’s. Hence, the space complexity will be O(M \ N)* , where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix.
Code (DFS) (DFS with visited matrix)
1 | # 过leetcode |
Code (BFS)
Here is what our BFS algorithm will look like. We will update the input matrix to mark cells visited.
1 | # BFS一般使用queue,很少见递归 |
Time Complexity
Time complexity of the above algorithm will be O(M * N), where ‘M’ is the number of rows and ‘N’ is the number of columns.
Space Complexity
Space complexity of the above algorithm will be *O(min(M, N)). In the worst case, when the matrix is completely filled with land cells, the size of the queue can grow up to min(M, N).
Code (BFS with visited matrix)
Here is what our BFS algorithm will look like. We will keep a separate boolean matrix to record whether or not each cell has been visited.
1 | from collections import deque |
Time Complexity
Time complexity of the above algorithm will be O(M \ N)*, where ‘M’ is the number of rows and ‘N’ is the number of columns.
Space Complexity
Because of the visited array and max size of the queue, the space complexity will be O(M \ N)*, where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix.
Biggest Island
695. Max Area of Island Design Gurus
Problem Statement
Given a 2D array (i.e., a matrix) containing only 1s (land) and 0s (water), find the biggest island in it. Write a function to return the area of the biggest island.
An island is a connected set of 1s (land) and is surrounded by either an edge or 0s (water). Each cell is considered connected to other cells horizontally or vertically (not diagonally).
Example 1
Input: matrix =
Output: 5
Explanation: The matrix has three islands. The biggest island has 5 cells .
Constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 50
matrix[i][j] is '0' or '1'.
Solution
The question follows the Island pattern and is quite similar to Number of Islands problem.
We will traverse the matrix linearly to find islands.
Whenever we find a cell with the value ‘1’ (i.e., land), we have found an island. Using that cell as the root node, we will perform a Depth First Search (DFS) or Breadth First Search (BFS) to find all of its connected land cells. During our DFS or BFS traversal, we will find and mark all the horizontally and vertically connected land cells.
We will keep a variable to remember the max area of any island.
Algorithm Walkthrough
Here is the detailed walkthrough of the DFS algorithm:
- We first initialize
biggestIslandArea
to 0. This variable will keep track of the largest island’s area we have encountered so far. - Then, we traverse each cell in the matrix. If the cell’s value is 1 (land), we begin a DFS search from this cell using the
visitIslandDFS
function. This function will visit the cell and all its neighboring cells that are part of the same island. - In the
visitIslandDFS
function, we first check if the current cell (x, y) is within the boundaries of the matrix and if it’s a land cell. If it’s not, we return 0. - We then mark the current cell as visited by setting its value to 0 (water). This helps avoid visiting the same cell again and ending up in an infinite loop.
- We initialize the
area
of the current island to 1 (counting the current cell), and then add to it the areas returned by the recursive DFS calls for the neighboring cells (top, bottom, left, and right). - After we finish the DFS for a cell (meaning we have visited all cells in the island that the cell is a part of), we update
biggestIslandArea
with the maximum of its current value and the area of the island we just finished exploring. - Finally, after traversing all cells in the matrix, we return
biggestIslandArea
, which now holds the area of the largest island.
Here is the visual representation of the algorithm:
Code (DFS)
Here is what our DFS algorithm will look like. We will update the input matrix to mark nodes visited.
1 | # 官方使用的是DFS的递归,但是我比较习惯使用while |
Complexity Analysis
Time Complexity
Time complexity of the above algorithm will be O(M * N), where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix. This is due to the fact that we have to traverse the whole matrix to find islands.
Space Complexity
DFS recursion stack can go O(M * N) deep when the whole matrix is filled with ‘1’s. Hence, the space complexity will be O(M * N), where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix.
Flood Fill
733. Flood Fill Design Gurus
Problem Statement
Any image can be represented by a 2D integer array (i.e., a matrix) where each cell represents the pixel value of the image.
Flood fill algorithm takes a starting cell (i.e., a pixel) and a color. The given color is applied to all horizontally and vertically connected cells with the same color as that of the starting cell. Recursively, the algorithm fills cells with the new color until it encounters a cell with a different color than the starting cell.
Given a matrix, a starting cell, and a color, flood fill the matrix.
Example 1:
Input: matrix =
starting cell = (1, 3)
new color = 2
Output:
Example 2:
Input: matrix =
starting cell = (3, 2)
new color = 5
Output:
Constraints:
m == matrix.length
n == - m == matrix[i].length
1 <= m, n <= 50
- 0 <= - m == matrix[i][j], color < 216
0 <= x < m
0 <= y < n
Solution
The question follows the Island pattern and is quite similar to Number of Islands problem.
From the given starting cell, we can perform a Depth First Search (DFS) or Breadth First Search (BFS) to find all of its connected cells with the same color. During our DFS or BFS traversal, we will update the cells with the new color.
Following is the DFS or BFS traversal of the example-2 mentioned above:
Code (DFS)
Here is what our DFS algorithm will look like:
1 | # 官方使用的是DFS的递归,但是我比较习惯使用while |
Time Complexity
Time complexity the above algorithm will be O(M * N), where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix. This is due to the fact that, in the worst case, we might have to fill the whole matrix.
Space Complexity
DFS recursion stack can go O(M * N) deep when we have to fill the whole matrix. Hence, the space complexity will be O(M * N) , where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix.
Number of Closed Islands
Similar | 1254. Number of Closed Islands Design Gurus Leetcode 中 ‘0’ and ‘1’的含义反过来了,所以只要改一下这个就过了
Problem Statement
You are given a 2D matrix containing only 1s (land) and 0s (water).
An island is a connected set of 1s (land) and is surrounded by either an edge or 0s (water). Each cell is considered connected to other cells horizontally or vertically (not diagonally).
A closed island is an island that is totally surrounded by 0s (i.e., water). This means all horizontally and vertically connected cells of a closed island are water. This also means that, by definition, a closed island can’t touch an edge (as then the edge cells are not connected to any water cell).
Write a function to find the number of closed islands in the given matrix.
Example 1
Input: matrix =
Output: 1 Explanation: The given matrix has two islands, but only the highlighted island is a closed island. The other island is touching the boundary that’s why is is not considered a closed island.
Example 2
Input: matrix =
Output: 2
Explanation: The given matrix has two islands and both of them are closed islands.
Constraints:
1 <= grid.length, grid[0].length <= 100
0 <= grid[i][j] <=1
Solution
The question follows the Island pattern and is quite similar to Number of Islands problem.
We will traverse the matrix linearly to find islands. We can use the Depth First Search (DFS) or Breadth First Search (BFS) to traverse an island i.e., to find all of its connected land cells.
How do we decide if an island is a closed island?
To find that out, while traversing an island we need to ensure two things:
- The island does not touch an edge.
- Outside boundary of the island are water cells.
For the first condition, whenever we go outside the boundary of the matrix during DFS or BFS, it means that one of the cells of the island is touching an edge; so, the island is not closed. Following code will cover this condition:
1 | if (x < 0 || x >= matrix.length || y < 0 || y >= matrix[0].length) |
For the second condition, we need to ensure that all the boundary cells of the island are water. Following code will take care of that:
1 | if (matrix[x][y] == 0 || visited[x][y]) |
Here is the visual representation of the algorithm:
Code (DFS)
Here is what our DFS algorithm will look like. We will use a separate array to mark nodes visited.
1 | # 官方使用的是DFS的递归,但是我比较习惯使用while |
Time Complexity
Time complexity of the above algorithm will be O(M * N), where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix. This is due to the fact that we have to traverse the whole matrix to find islands.
Space Complexity
DFS recursion stack can go MN deep when the whole matrix is filled with ‘1’s. Hence, the space complexity will be **O(M \ N)**, where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix.
Problem Challenge 1
463. Island Perimeter Design Gurus
Problem Statement
You are given a 2D matrix containing only 1s (land) and 0s (water).
An island is a connected set of 1s (land) and is surrounded by either an edge or 0s (water). Each cell is considered connected to other cells horizontally or vertically (not diagonally).
There are no lakes on the island, so the water inside the island is not connected to the water around it. A cell is a square with a side length of 1..
The given matrix has only one island, write a function to find the perimeter of that island.
Example 1
Input: matrix =
Output: 14
Explanation: The boundary of the island constitutes 14 sides.
Example 2
Input: matrix =
Output: 12
Explanation: The boundary of the island constitute 12 sides.
Solution
The question follows the Island pattern and is quite similar to Number of Islands problem.
We will traverse the matrix linearly to find the island. We can use the Depth First Search (DFS) or Breadth First Search (BFS) to traverse the island i.e., to find all of its connected land cells.
How do we calculate the boundary if the island?
Each cell has four sides. Each side of an island cell can be shared with another cell; we can include the side in the island perimeter only if the other cell is a water.
If a cell side is on boundary, we should include that side in the perimeter.
Following piece of code will cover these two conditions:
1 | if (x < 0 || x >= matrix.length || y < 0 || y >= matrix[0].length) |
Code (DFS)
Here is what our DFS algorithm will look like. We will use a separate matrix to mark nodes visited.
1 | # 官方使用的是DFS的递归,但是我比较习惯使用while |
Time Complexity
Time complexity of the above algorithm will be O(M * N), where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix. This is due to the fact that we have to traverse the whole matrix to find the island.
Space Complexity
DFS recursion stack can go O(M * N) deep when the whole matrix is filled with ‘1’s. Hence, the space complexity will be O(M * N), where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix.
Problem Challenge 2
Leetcode 会员 Design Gurus
Problem Statement
You are given a 2D matrix containing only 1s (land) and 0s (water).
An island is a connected set of 1s (land) and is surrounded by either an edge or 0s (water). Each cell is considered connected to other cells horizontally or vertically (not diagonally).
Two islands are considered the same if and only if they can be translated (not rotated or reflected) to equal each other.
Write a function to find the number of distinct islands in the given matrix.
Example 1
Input: matrix =
Output: 2
Explanation: There are four islands in the given matrix, but three of them are the same; hence, there are only two distinct islands.
Example 2
Input: matrix =
Output: 2
Explanation: There are three islands in the given matrix, but two of them are the same; hence, there are only two distinct islands.
Solution
The question follows the Island pattern and is quite similar to Number of Islands problem.
We will traverse the matrix linearly to find islands. We can use the Depth First Search (DFS) or Breadth First Search (BFS) to traverse an island i.e., to find all of its connected land cells.
How do we decide if two islands are same?
If two islands are same, their traversal path should be same too. This means, if we perform a DFS or BFS on two equal islands starting from their top-left cell, the traversal pattern should be exactly same for both the islands. For example, here is the DFS traversal of the example-2 mentioned above:
We can clearly see that the two equal islands have same traversal pattern.
We can utilize this fact to develop an algorithm.
While traversing an island, we can construct a string that maps the traversal path of the island. For example, here is the DFS traversal of the two same islands mentioned in Example-2 ( ‘R’ for right move, ‘D’ for down move, ‘O’ for origin denoting the start): ORDR
We can start inserting these traversal strings of each island in a HashSet. This will ensure that we will not have any duplicate traversal string in the HashSet, thus giving us distinct islands. When we finish traversing the matrix, the HashSet will contain the distinct traversal path of all islands. Hence, the total number of elements in the HashSet will be equal to distinct number of islands.
Code
Here is the code for this algorithm:
1 | # 官方使用的是DFS的递归,但是我比较习惯使用while |
Time Complexity
Time complexity of the above algorithm will be O(M * N), where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix. This is due to the fact that we have to traverse the whole matrix to find islands.
Space Complexity
DFS recursion stack can go MN deep when the whole matrix is filled with ‘1’s. Hence, the space complexity will be **O(M \ N)**, where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix.
Problem Challenge 3
1559. Detect Cycles in 2D Grid Design Gurus
Problem Statement
You are given a 2D matrix containing different characters, you need to find if there exists any cycle consisting of the same character in the matrix.
A cycle is a path in the matrix that starts and ends at the same cell and has four or more cells. From a given cell, you can move to one of the cells adjacent to it - in one of the four directions (up, down, left, or right), if it has the same character value of the current cell.
Write a function to find if the matrix has a cycle.
Example 1
Input: matrix =
Output: true
Explanation: The given matrix has a cycle as shown below:
Example 2
Input: matrix =
Output: true
Explanation: The given matrix has one cycle as shown below:
Example 3
Input: matrix =
Output: false
Explanation: The given matrix has no cycle.
Constraints:
- m == matrix.length
- n == matrix[i].length
- 1 <= m, n <= 500
- matrix[i][j] is ‘0’ or ‘1’.
Solution
The question follows the Island pattern and is quite similar to Number of Islands problem.
We will traverse the matrix linearly to find any cycle. Each cycle is like an island having cells containing same values. Hence, we can use the Depth First Search (DFS) or Breadth First Search (BFS) to traverse a cycle i.e., to find all of its connected cells with the same value.
Our approach for traversing the matrix will be similar to the one we used when searching for islands. We will keep another matrix to remember the cells that we have visited. From any given cell, we can perform DFS to traverse all the neighboring cells having the same character value.
Whenever we reach a cell that have already been visited, we can conclude that we have found a cycle. This also means that we need to be careful to not start traversing the parent cell and wrongly finding a cycle. That is, while traversing, when initiating DFS recursive calls to all the neighboring cell, we should not start a DFS call to the pervious cell, Here is the visual representation of the algorithm:
Code
Here is the code for this algorithm:
1 | # 官方使用的是DFS的递归,但是我比较习惯使用while |
Time Complexity
Time complexity of the above algorithm will be O(M * N), where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix. This is due to the fact that we have to traverse the whole matrix to find cycles.
Space Complexity
DFS recursion stack can go MN deep when the whole matrix is filled with the same character. Hence, the space complexity will be **O(M \ N)**, where ‘M’ is the number of rows and ‘N’ is the number of columns of the input matrix.