
Problem Statement
In this problem, you are provided with an m x n
binary matrix called grid
, which represents a map where 1
indicates land and 0
indicates water. An island is a contiguous group of 1
s connected either horizontally or vertically but not diagonally. The task is to identify distinct islands in this grid. Distinct islands are islands that have the same shape and can be translated (shifted in any direction without rotation or reflection) to match exactly with another island. The challenge is to find the total number of such distinct islands present in the matrix.
Examples
Example 1
Input:
grid = [[1,1,0,0,0],[1,1,0,0,0],[0,0,0,1,1],[0,0,0,1,1]]
Output:
1
Example 2
Input:
grid = [[1,1,0,1,1],[1,0,0,0,0],[0,0,0,0,1],[1,1,0,1,1]]
Output:
3
Constraints
m == grid.length
n == grid[i].length
1 <= m, n <= 50
grid[i][j]
is either0
or1
.
Approach and Intuition
To solve this problem, we have to systematically explore each element of the grid, and when we find a land cell (1
), we should perform a depth-first search (DFS) or breadth-first search (BFS) to track the entire island structure. Here's an outlined approach:
- Initialize visitation tracking, typically using a set or matrix to keep track of which cells have been visited.
- Traverse the matrix cell by cell. When you encounter an unvisited
1
, you initiate a DFS or BFS from that cell. - For tracking whether two islands are the same, besides marking the visited cells, use a pattern or a path signature strategy. For example, as you perform DFS, you can record the direction moves (up, down, left, right represented perhaps as 'U', 'D', 'L', 'R') relative to the starting cell of the traversal. This string can serve as a unique identifier for the shape and structure of an island.
- Store each unique island signature in a set — since sets automatically handle duplicates, any repeated island shape will not be added again.
- The final count of distinct islands will be the size of this set of unique island signatures.
Key challenges and considerations include:
- Boundary conditions need careful handling to ensure searches do not go out of the grid limits.
- Efficiently differentiating between island shapes and efficiently storing and comparing these shapes.
- Ensuring complete visitation of each potential island part once an island cell is found.
Examples from the prompt:
- In Example 1, the grid forms one island that repeats itself. Thus, despite the island appearing twice, the answer is 1.
- In Example 2, different configurations and disconnected parts mean there are a total of 3 distinct islands.
The constraints (1 <= m, n <= 50
) allow for a full exploration of the grid without the need for exceptionally complex optimizations.
Solutions
- Java
class IslandCounter {
private int[][] matrix;
private boolean[][] checked;
private StringBuilder islandShape;
public int countUniqueIslands(int[][] matrix) {
this.matrix = matrix;
this.checked = new boolean[matrix.length][matrix[0].length];
Set<String> uniqueIslands = new HashSet<>();
for (int x = 0; x < matrix.length; x++) {
for (int y = 0; y < matrix[0].length; y++) {
islandShape = new StringBuilder();
explore(x, y, '0');
if (islandShape.length() == 0) {
continue;
}
uniqueIslands.add(islandShape.toString());
}
}
return uniqueIslands.size();
}
private void explore(int x, int y, char direction) {
if (x < 0 || y < 0 || x >= matrix.length || y >= matrix[0].length) {
return;
}
if (checked[x][y] || matrix[x][y] == 0) {
return;
}
checked[x][y] = true;
islandShape.append(direction);
explore(x + 1, y, 'D');
explore(x - 1, y, 'U');
explore(x, y + 1, 'R');
explore(x, y - 1, 'L');
islandShape.append('0');
}
}
The solution provided tackles the problem of determining the number of distinct islands in a 2D grid. Each island is made up of connected land cells (represented by 1s) separated by water cells (represented by 0s). The distinction of each island is based on its shape rather than just the count of cells.
Here is an outline that summarizes the approach implemented in your Java code:
- Initialize a class
IslandCounter
with a private 2D integer arraymatrix
for the grid and a 2D boolean arraychecked
to keep track of the cells that have already been visited. - Declare a
StringBuilder
islandShape
to dynamically record the shape of the island during exploration. - Implement the
countUniqueIslands
function which:- Takes a 2D integer array
matrix
. - Initializes the
checked
array to ensure all cells are initially set as not visited. - Uses a
HashSet
uniqueIslands
to store unique island shapes – uniqueness determined by their navigation path string created during the exploration. - Iterates through each cell in the matrix, using the helper function
explore
to navigate through the island from each unvisited land cell, concatenating directions to theislandShape
to form a unique identifier for the shape of the island. - Adds the completed island shape to the set of unique islands if not seen before.
- Returns the size of
uniqueIslands
set, which corresponds to the number of distinct islands.
- Takes a 2D integer array
- The
explore
function:- Is a recursive function that receives coordinates
(x, y)
and the direction from which it was called. - Base case checks ensure it does not explore out of bounds or revisit cells or traverse water cells.
- Marks the cell as visited and updates the
islandShape
with the direction moved. - Recursively calls itself for the four possible directions (up, down, left, right).
- Upon returning from each recursive call, appends a termination mark to signal the end of that path sequence, aiding in distinguishing between different structures.
- Is a recursive function that receives coordinates
Implement this solution effectively ensures that each distinct shape of the island is recognized, counting only truly unique islands. The inclusion of navigation paths in the shape definition is key to distinguishing between islands of similar sizes but different configurations.
- Python
class Solution:
def countUniqueIslands(self, matrix: List[List[int]]) -> int:
def exploreIsland(x, y, dir):
if x < 0 or y < 0 or x >= len(matrix) or y >= len(matrix[0]):
return
if (x, y) in visited or matrix[x][y] == 0:
return
visited.add((x, y))
island_pattern.append(dir)
exploreIsland(x + 1, y, "D")
exploreIsland(x - 1, y, "U")
exploreIsland(x, y + 1, "R")
exploreIsland(x, y - 1, "L")
island_pattern.append("back")
visited = set()
distinct_islands = set()
for i in range(len(matrix)):
for j in range(len(matrix[0])):
island_pattern = []
exploreIsland(i, j, "start")
if island_pattern:
distinct_islands.add(tuple(island_pattern))
return len(distinct_islands)
The provided code defines a solution for determining the number of distinct islands in a given 2D matrix where islands are represented with 1
s and water with 0
s.
Ensure the matrix is passed to the countUniqueIslands
function. The function employs a nested helper function named exploreIsland
, which uses a depth-first search (DFS) approach to traverse the island and capture its unique shape. This is accomplished using directions as markers during the traversal, allowing for a distinctive pattern representation of each island.
- The algorithm starts by initializing a
visited
set to keep track of visited grid cells and adistinct_islands
set to store unique patterns of islands. - Iteration through the matrix cells occurs, and for each unvisited cell marked by a
1
,exploreIsland
is invoked. - The
exploreIsland
performs DFS from the current cell in all four cardinal directions (Down, Up, Right, Left), appending the move direction to theisland_pattern
list and marking the position as visited. - Upon retracing steps in the DFS ('backtracking'), the word "back" is added to the pattern.
- Once an island pattern traversal is completed, its tuple representation (to ensure immutability and hashability) is added to
distinct_islands
if it's not already present. - The main function returns the count of distinct island patterns found by converting the length of the
distinct_islands
set to an integer.
In summary, the function uniquely identifies islands based on their shape and relative cell positions within the matrix, disregarding identical islands' different locations. This Python solution is efficient, leveraging set operations for quick look-ups and ensuring no redundant pattern storage through unique tuple checks.
No comments yet.