Problem

You are given an m x n binary matrix grid. An island is a group of 1’s (representing land) connected 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water.

An island is considered to be the same as another if and only if one island can be translated (and not rotated or reflected) to equal the other.

Return the number ofdistinct islands.

Examples

Example 1:

1
2
3
![](https://fastly.jsdelivr.net/gh/doocs/leetcode@main/solution/0600-0699/0694.Number%20of%20Distinct%20Islands/images/distinctisland1-1-grid.jpg)
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:

1
2
3
![](https://fastly.jsdelivr.net/gh/doocs/leetcode@main/solution/0600-0699/0694.Number%20of%20Distinct%20Islands/images/distinctisland1-2-grid.jpg)
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 either 0 or 1.

Solution

Method 1 – DFS/BFS with Shape Encoding

Intuition

To count distinct islands, we need to encode the shape of each island in a way that is invariant to translation. The simplest way is to record the relative positions of all cells in an island compared to the starting cell.

Approach

  1. For each unvisited land cell, start a DFS/BFS and record the path (relative moves or coordinates).
  2. Store each island’s shape in a set to ensure uniqueness.
  3. The answer is the size of the set.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <vector>
#include <set>
using namespace std;
class Solution {
public:
    void dfs(vector<vector<int>>& grid, int x, int y, int baseX, int baseY, vector<pair<int,int>>& shape) {
        int m = grid.size(), n = grid[0].size();
        if (x<0||y<0||x>=m||y>=n||grid[x][y]==0) return;
        grid[x][y]=0;
        shape.push_back({x-baseX, y-baseY});
        dfs(grid,x+1,y,baseX,baseY,shape);
        dfs(grid,x-1,y,baseX,baseY,shape);
        dfs(grid,x,y+1,baseX,baseY,shape);
        dfs(grid,x,y-1,baseX,baseY,shape);
    }
    int numDistinctIslands(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        set<vector<pair<int,int>>> shapes;
        for (int i=0;i<m;++i) for (int j=0;j<n;++j) if (grid[i][j]) {
            vector<pair<int,int>> shape;
            dfs(grid,i,j,i,j,shape);
            shapes.insert(shape);
        }
        return shapes.size();
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
func numDistinctIslands(grid [][]int) int {
    m, n := len(grid), len(grid[0])
    shapes := map[string]struct{}{}
    var dfs func(x, y, baseX, baseY int, shape *[]string)
    dfs = func(x, y, baseX, baseY int, shape *[]string) {
        if x<0||y<0||x>=m||y>=n||grid[x][y]==0 { return }
        grid[x][y]=0
        *shape = append(*shape, fmt.Sprintf("%d_%d", x-baseX, y-baseY))
        dfs(x+1,y,baseX,baseY,shape)
        dfs(x-1,y,baseX,baseY,shape)
        dfs(x,y+1,baseX,baseY,shape)
        dfs(x,y-1,baseX,baseY,shape)
    }
    for i:=0;i<m;i++ { for j:=0;j<n;j++ { if grid[i][j]==1 {
        shape := []string{}
        dfs(i,j,i,j,&shape)
        key := strings.Join(shape, ",")
        shapes[key]=struct{}{}
    }}}
    return len(shapes)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.*;
class Solution {
    public int numDistinctIslands(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        Set<String> shapes = new HashSet<>();
        for (int i=0;i<m;i++) for (int j=0;j<n;j++) if (grid[i][j]==1) {
            List<String> shape = new ArrayList<>();
            dfs(grid,i,j,i,j,shape);
            shapes.add(String.join(",", shape));
        }
        return shapes.size();
    }
    void dfs(int[][] grid, int x, int y, int baseX, int baseY, List<String> shape) {
        int m = grid.length, n = grid[0].length;
        if (x<0||y<0||x>=m||y>=n||grid[x][y]==0) return;
        grid[x][y]=0;
        shape.add((x-baseX)+"_"+(y-baseY));
        dfs(grid,x+1,y,baseX,baseY,shape);
        dfs(grid,x-1,y,baseX,baseY,shape);
        dfs(grid,x,y+1,baseX,baseY,shape);
        dfs(grid,x,y-1,baseX,baseY,shape);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
    fun numDistinctIslands(grid: Array<IntArray>): Int {
        val m = grid.size; val n = grid[0].size
        val shapes = mutableSetOf<String>()
        fun dfs(x: Int, y: Int, baseX: Int, baseY: Int, shape: MutableList<String>) {
            if (x<0||y<0||x>=m||y>=n||grid[x][y]==0) return
            grid[x][y]=0
            shape.add("${x-baseX}_${y-baseY}")
            dfs(x+1,y,baseX,baseY,shape)
            dfs(x-1,y,baseX,baseY,shape)
            dfs(x,y+1,baseX,baseY,shape)
            dfs(x,y-1,baseX,baseY,shape)
        }
        for (i in 0 until m) for (j in 0 until n) if (grid[i][j]==1) {
            val shape = mutableListOf<String>()
            dfs(i,j,i,j,shape)
            shapes.add(shape.joinToString(","))
        }
        return shapes.size
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution:
    def numDistinctIslands(self, grid: List[List[int]]) -> int:
        m, n = len(grid), len(grid[0])
        shapes = set()
        def dfs(x, y, baseX, baseY, shape):
            if x<0 or y<0 or x>=m or y>=n or grid[x][y]==0: return
            grid[x][y]=0
            shape.append((x-baseX, y-baseY))
            dfs(x+1,y,baseX,baseY,shape)
            dfs(x-1,y,baseX,baseY,shape)
            dfs(x,y+1,baseX,baseY,shape)
            dfs(x,y-1,baseX,baseY,shape)
        for i in range(m):
            for j in range(n):
                if grid[i][j]:
                    shape = []
                    dfs(i,j,i,j,shape)
                    shapes.add(tuple(shape))
        return len(shapes)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
use std::collections::HashSet;
impl Solution {
    pub fn num_distinct_islands(grid: Vec<Vec<i32>>) -> i32 {
        let m = grid.len(); let n = grid[0].len();
        let mut grid = grid;
        let mut shapes = HashSet::new();
        fn dfs(grid: &mut Vec<Vec<i32>>, x: i32, y: i32, base_x: i32, base_y: i32, shape: &mut Vec<(i32,i32)>) {
            let m = grid.len() as i32; let n = grid[0].len() as i32;
            if x<0||y<0||x>=m||y>=n||grid[x as usize][y as usize]==0 { return; }
            grid[x as usize][y as usize]=0;
            shape.push((x-base_x, y-base_y));
            dfs(grid,x+1,y,base_x,base_y,shape);
            dfs(grid,x-1,y,base_x,base_y,shape);
            dfs(grid,x,y+1,base_x,base_y,shape);
            dfs(grid,x,y-1,base_x,base_y,shape);
        }
        for i in 0..m as i32 {
            for j in 0..n as i32 {
                if grid[i as usize][j as usize]==1 {
                    let mut shape = vec![];
                    dfs(&mut grid,i,j,i,j,&mut shape);
                    shapes.insert(shape);
                }
            }
        }
        shapes.len() as i32
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
function numDistinctIslands(grid: number[][]): number {
    const m = grid.length, n = grid[0].length;
    const shapes = new Set<string>();
    function dfs(x: number, y: number, baseX: number, baseY: number, shape: string[]) {
        if (x<0||y<0||x>=m||y>=n||grid[x][y]==0) return;
        grid[x][y]=0;
        shape.push(`${x-baseX}_${y-baseY}`);
        dfs(x+1,y,baseX,baseY,shape);
        dfs(x-1,y,baseX,baseY,shape);
        dfs(x,y+1,baseX,baseY,shape);
        dfs(x,y-1,baseX,baseY,shape);
    }
    for (let i=0;i<m;i++) for (let j=0;j<n;j++) if (grid[i][j]==1) {
        const shape: string[] = [];
        dfs(i,j,i,j,shape);
        shapes.add(shape.join(","));
    }
    return shapes.size;
}

Complexity

  • ⏰ Time complexity: O(mn)
  • 🧺 Space complexity: O(mn)