{x}
blog image

Number of Distinct Islands

Solution Explanation:

This problem asks to find the number of distinct islands in a binary matrix. An island is a group of connected '1's. Two islands are considered the same if one can be translated to match the other (without rotation or reflection).

The solution uses Depth-First Search (DFS) to traverse each island and record its shape. The shape is encoded as a string representing the relative directions taken during the traversal. By storing these shape strings in a set, we can efficiently count the number of unique island shapes.

Approach:

  1. DFS Traversal: The core of the solution is a DFS function that explores an island. It starts at a cell containing '1', marks the cell as visited (by setting it to '0'), and recursively explores its neighbors (up, down, left, right).

  2. Path Encoding: During the DFS traversal, we record the direction taken to reach each visited cell relative to the starting cell of the island. This is achieved by encoding each step as a number (0, 1, 2, 3 for up, right, down, left, respectively).

  3. Island Shape Representation: The sequence of directions forms a path representing the island's shape. These paths are converted to strings for easy storage in a set. The path string is constructed such that it includes backward paths.

  4. Unique Island Counting: The paths set stores unique shape strings. We iterate through the grid. If we find a '1', we perform DFS on that island, generate its path string, and add it to the set. The final size of the set represents the number of distinct islands.

Time and Space Complexity:

  • Time Complexity: O(M * N), where M and N are the dimensions of the grid. In the worst case, we visit each cell once during the DFS traversal.
  • Space Complexity: O(M * N) in the worst case to store the path strings for all islands (it's actually less because of the set). The recursion depth for DFS is at most min(M, N)

Code Explanation (Python3 as Example):

class Solution:
    def numDistinctIslands(self, grid: List[List[int]]) -> int:
        def dfs(i: int, j: int, k: int):
            grid[i][j] = 0
            path.append(str(k))
            dirs = (-1, 0, 1, 0, -1)  # Directions: up, right, down, left
            for h in range(1, 5):
                x, y = i + dirs[h - 1], j + dirs[h]
                if 0 <= x < m and 0 <= y < n and grid[x][y]:
                    dfs(x, y, h)
            path.append(str(-k)) #Adding backtracking steps for accurate path representation
 
 
        paths = set()
        path = []
        m, n = len(grid), len(grid[0])
        for i, row in enumerate(grid):
            for j, x in enumerate(row):
                if x:
                    dfs(i, j, 0)
                    paths.add("".join(path))
                    path.clear()
        return len(paths)
 

The other languages (Java, C++, Go, Typescript) follow a very similar logic, adapting the syntax and data structures to their respective languages. The key concepts of DFS, path encoding, and using a set to track unique shapes remain the same.