Find the number of distinct islands in a 2D matrix

Last Updated : 15 Aug, 2026

Given a grid grid[][] of size n × m, consisting of characters 'L' and 'W', where 'L' represents Land and 'W' represents Water, find the number of distinct islands in the grid. An island is a group of one or more land cells connected horizontally or vertically.

  • Two islands are considered distinct if their shapes are different.
  • Two islands have the same shape if one can be translated to match the other exactly. Rotation and reflection are not allowed.

Examples:

Input: grid[][] = [['L', 'L', 'W', 'W', 'W'], ['L', 'L', 'W', 'W', 'W'], ['W', 'W', 'W', 'L', 'L'], ['W', 'W', 'W', 'L', 'L']]
Output: 1
Explanation: The grid contains two islands. Both islands have the same shape (a 2 × 2 block of land), so they are counted as a single distinct island.

blobid1_1781703111


Input: grid[][] = [['L', 'L', 'W', 'L', 'L'], ['L', 'W', 'W', 'W', 'W'], ['W', 'W', 'W', 'W', 'L'], ['L', 'L', 'W', 'L', 'L']]
Output: 3
Explanation: There are four islands in the grid. Two islands have the same shape, while the other two have different shapes. Therefore, the number of distinct island shapes is 3.

blobid2_1781703222
Try It Yourself
redirect icon

[Naive Approach] Store and Compare Island Shapes - O((n × m)^2) Time and O(n × m) Space

The idea is to find every island using DFS and store its shape as relative coordinates. For each new island, compare its shape with all previously discovered island shapes. If no matching shape exists, count it as a new distinct island.

C++
#include <bits/stdc++.h>
using namespace std;

void dfs(vector<vector<char>> &grid, int baseRow, int baseCol, int row, int col,
         vector<pair<int, int>> &shape)
{
    int n = grid.size();
    int m = grid[0].size();

    if (row < 0 || row >= n || col < 0 || col >= m || grid[row][col] != 'L')
    {
        return;
    }

    // Mark current cell as visited
    grid[row][col] = '#';

    // Store relative coordinates
    shape.push_back({row - baseRow, col - baseCol});

    dfs(grid, baseRow, baseCol, row - 1, col, shape);
    dfs(grid, baseRow, baseCol, row + 1, col, shape);
    dfs(grid, baseRow, baseCol, row, col - 1, shape);
    dfs(grid, baseRow, baseCol, row, col + 1, shape);
}

int countDistinctIslands(vector<vector<char>> &grid)
{
    int n = grid.size();
    int m = grid[0].size();

    // Stores all distinct island shapes
    vector<vector<pair<int, int>>> distinctShapes;

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (grid[i][j] == 'L')
            {
                vector<pair<int, int>> shape;

                // Find shape of current island
                dfs(grid, i, j, i, j, shape);

                bool found = false;

                // Compare with previously found shapes
                for (auto &prevShape : distinctShapes)
                {
                    if (prevShape == shape)
                    {
                        found = true;
                        break;
                    }
                }

                // Store shape if it is unique
                if (!found)
                {
                    distinctShapes.push_back(shape);
                }
            }
        }
    }

    return distinctShapes.size();
}

// Driver Code
int main()
{
    int n = 4, m = 5;

    vector<vector<char>> grid = {{'L', 'W', 'W', 'L', 'W'},
                                 {'L', 'W', 'W', 'L', 'W'},
                                 {'W', 'W', 'W', 'L', 'L'},
                                 {'L', 'L', 'W', 'W', 'W'}};

    cout << countDistinctIslands(grid);

    return 0;
}
Java
import java.util.ArrayList;

class GFG {

    static void dfs(char[][] grid, int baseRow, int baseCol,
                    int row, int col,
                    ArrayList<String> shape)
    {
        int n = grid.length;
        int m = grid[0].length;

        if (row < 0 || row >= n || col < 0 || col >= m
            || grid[row][col] != 'L') {
            return;
        }

        // Mark current cell as visited
        grid[row][col] = '#';

        // Store relative coordinates
        shape.add((row - baseRow) + "," + (col - baseCol));

        dfs(grid, baseRow, baseCol, row - 1, col, shape);
        dfs(grid, baseRow, baseCol, row + 1, col, shape);
        dfs(grid, baseRow, baseCol, row, col - 1, shape);
        dfs(grid, baseRow, baseCol, row, col + 1, shape);
    }

    static int countDistinctIslands(char[][] grid)
    {
        int n = grid.length;
        int m = grid[0].length;

        // Stores all distinct island shapes
        ArrayList<ArrayList<String> > distinctShapes
            = new ArrayList<>();

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 'L') {
                    ArrayList<String> shape
                        = new ArrayList<>();

                    // Find shape of current island
                    dfs(grid, i, j, i, j, shape);

                    boolean found = false;

                    // Compare with previously found shapes
                    for (ArrayList<String> prevShape :
                         distinctShapes) {
                        if (prevShape.equals(shape)) {
                            found = true;
                            break;
                        }
                    }

                    // Store shape if it is unique
                    if (!found) {
                        distinctShapes.add(shape);
                    }
                }
            }
        }

        return distinctShapes.size();
    }

    public static void main(String[] args)
    {
        int n = 4, m = 5;

        char[][] grid = { { 'L', 'W', 'W', 'L', 'W' },
                          { 'L', 'W', 'W', 'L', 'W' },
                          { 'W', 'W', 'W', 'L', 'L' },
                          { 'L', 'L', 'W', 'W', 'W' } };

        System.out.println(countDistinctIslands(grid));
    }
}
Python
def dfs(grid, baseRow, baseCol, row, col, shape):
    n = len(grid)
    m = len(grid[0])

    if row < 0 or row >= n or col < 0 or col >= m or grid[row][col] != 'L':
        return

    # Mark current cell as visited
    grid[row][col] = '#'

    # Store relative coordinates
    shape.append((row - baseRow, col - baseCol))

    dfs(grid, baseRow, baseCol, row - 1, col, shape)
    dfs(grid, baseRow, baseCol, row + 1, col, shape)
    dfs(grid, baseRow, baseCol, row, col - 1, shape)
    dfs(grid, baseRow, baseCol, row, col + 1, shape)


def countDistinctIslands(grid):
    n = len(grid)
    m = len(grid[0])

    # Stores all distinct island shapes
    distinctShapes = []

    for i in range(n):
        for j in range(m):
            if grid[i][j] == 'L':
                shape = []

                # Find shape of current island
                dfs(grid, i, j, i, j, shape)

                found = False

                # Compare with previously found shapes
                for prevShape in distinctShapes:
                    if prevShape == shape:
                        found = True
                        break

                # Store shape if it is unique
                if not found:
                    distinctShapes.append(shape)

    return len(distinctShapes)


if __name__ == "__main__":
    n, m = 4, 5

    grid = [
        ['L', 'W', 'W', 'L', 'W'],
        ['L', 'W', 'W', 'L', 'W'],
        ['W', 'W', 'W', 'L', 'L'],
        ['L', 'L', 'W', 'W', 'W']
    ]

    print(countDistinctIslands(grid))
C#
using System;
using System.Collections.Generic;

class GFG {

    static void dfs(char[,] grid, int baseRow, int baseCol,
                    int row, int col, List<string> shape)
    {
        int n = grid.GetLength(0);
        int m = grid.GetLength(1);

        if (row < 0 || row >= n || col < 0 || col >= m
            || grid[row, col] != 'L') {
            return;
        }

        // Mark current cell as visited
        grid[row, col] = '#';

        // Store relative coordinates
        shape.Add((row - baseRow) + "," + (col - baseCol));

        // 4-direction DFS
        dfs(grid, baseRow, baseCol, row - 1, col, shape);
        dfs(grid, baseRow, baseCol, row + 1, col, shape);
        dfs(grid, baseRow, baseCol, row, col - 1, shape);
        dfs(grid, baseRow, baseCol, row, col + 1, shape);
    }

    static int countDistinctIslands(char[,] grid)
    {
        int n = grid.GetLength(0);
        int m = grid.GetLength(1);

        // Stores all distinct island shapes
        List<List<string>> distinctShapes = new List<List<string>>();

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {

                if (grid[i, j] == 'L') {

                    List<string> shape = new List<string>();

                    // Find shape of current island
                    dfs(grid, i, j, i, j, shape);

                    bool found = false;

                    // Compare with previously stored shapes
                    foreach (List<string> prevShape in distinctShapes) {

                        if (prevShape.Count != shape.Count) {
                            continue;
                        }

                        bool same = true;

                        for (int k = 0; k < shape.Count; k++) {
                            if (prevShape[k] != shape[k]) {
                                same = false;
                                break;
                            }
                        }

                        if (same) {
                            found = true;
                            break;
                        }
                    }

                    // Store shape if it is unique
                    if (!found) {
                        distinctShapes.Add(shape);
                    }
                }
            }
        }

        return distinctShapes.Count;
    }

    static void Main()
    {
        char[,] grid = {
            { 'L', 'W', 'W', 'L', 'W' },
            { 'L', 'W', 'W', 'L', 'W' },
            { 'W', 'W', 'W', 'L', 'L' },
            { 'L', 'L', 'W', 'W', 'W' }
        };

        Console.WriteLine(countDistinctIslands(grid));
    }
}
JavaScript
function dfs(grid, baseRow, baseCol, row, col, shape)
{
    let n = grid.length;
    let m = grid[0].length;

    if (row < 0 || row >= n || col < 0 || col >= m
        || grid[row][col] !== "L") {
        return;
    }

    // Mark current cell as visited
    grid[row][col] = "#";

    // Store relative coordinates
    shape.push([ row - baseRow, col - baseCol ]);

    dfs(grid, baseRow, baseCol, row - 1, col, shape);
    dfs(grid, baseRow, baseCol, row + 1, col, shape);
    dfs(grid, baseRow, baseCol, row, col - 1, shape);
    dfs(grid, baseRow, baseCol, row, col + 1, shape);
}

function countDistinctIslands(grid)
{
    let n = grid.length;
    let m = grid[0].length;

    // Stores all distinct island shapes
    let distinctShapes = [];

    for (let i = 0; i < n; i++) {
        for (let j = 0; j < m; j++) {
            if (grid[i][j] === "L") {
                let shape = [];

                // Find shape of current island
                dfs(grid, i, j, i, j, shape);

                let found = false;

                // Compare with previously found shapes
                for (let prevShape of distinctShapes) {
                    if (JSON.stringify(prevShape)
                        === JSON.stringify(shape)) {
                        found = true;
                        break;
                    }
                }

                // Store shape if it is unique
                if (!found) {
                    distinctShapes.push(shape);
                }
            }
        }
    }

    return distinctShapes.length;
}

// driver code
let n = 4, m = 5;

let grid = [
    [ "L", "W", "W", "L", "W" ],
    [ "L", "W", "W", "L", "W" ],
    [ "W", "W", "W", "L", "L" ], [ "L", "L", "W", "W", "W" ]
];

console.log(countDistinctIslands(grid));

Output
3

[Expected Approach] Using Hash Set - O(n × m) Time and O(n × m) Space

The naive approach compares the shape of every newly discovered island with all previously stored island shapes. We can avoid these repeated comparisons by storing all island shapes in a Hash Set.

The key idea is to represent every island using the relative coordinates of its cells with respect to the first cell of that island. Thus, two islands having the same shape will produce the same representation, even if they occur at different positions in the grid.

Since HashSet stores only unique elements, identical island shapes are automatically considered the same.

Let us understand with example:
Input: n = 4, m = 5

  • Start scanning the grid from top-left. When an unvisited 'L' cell is found, run DFS and store all island cells as coordinates relative to the starting cell.
  • For the island starting at (0,0), the relative shape becomes [(0,0), (1,0)], which is inserted into the shapes set.
  • For the island starting at (0,3), DFS records the shape [(0,0), (1,0), (2,0), (2,1)], which is different from the first shape and is also inserted.
  • For the island starting at (3,0), the recorded shape is [(0,0), (0,1)]; this is again unique and gets inserted into the set.
  • After traversing the entire grid, the set contains 3 distinct shapes, so the answer returned is 3.
C++
#include <bits/stdc++.h>
using namespace std;

vector<vector<int>> dirs = {{0, -1}, {-1, 0}, {0, 1}, {1, 0}};

void dfs(vector<vector<char>> &grid, int x0, int y0, int i, int j, vector<pair<int, int>> &shape)
{
    int rows = grid.size(), cols = grid[0].size();

    if (i < 0 || i >= rows || j < 0 || j >= cols || grid[i][j] != 'L')
        return;

    // Mark as visited
    grid[i][j] = '#';

    // Store position relative to the starting cell
    shape.push_back({i - x0, j - y0});

    for (auto &dir : dirs)
    {
        dfs(grid, x0, y0, i + dir[0], j + dir[1], shape);
    }
}

int countDistinctIslands(vector<vector<char>> &grid)
{
    int rows = grid.size();
    int cols = grid[0].size();

    set<vector<pair<int, int>>> shapes;

    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            if (grid[i][j] != 'L')
                continue;

            vector<pair<int, int>> shape;
            dfs(grid, i, j, i, j, shape);
            shapes.insert(shape);
        }
    }

    return (int)shapes.size();
}

// Driver Code
int main()
{
    int n = 4, m = 5;

    vector<vector<char>> grid = {{'L', 'W', 'W', 'L', 'W'},
                                 {'L', 'W', 'W', 'L', 'W'},
                                 {'W', 'W', 'W', 'L', 'L'},
                                 {'L', 'L', 'W', 'W', 'W'}};

    cout << countDistinctIslands(grid);

    return 0;
}
Java
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;

class GFG {

    static int[][] dirs
        = { { 0, -1 }, { -1, 0 }, { 0, 1 }, { 1, 0 } };

    static void dfs(char[][] grid, int x0, int y0, int i,
                    int j, ArrayList<String> shape)
    {
        int rows = grid.length, cols = grid[0].length;

        if (i < 0 || i >= rows || j < 0 || j >= cols
            || grid[i][j] != 'L')
            return;

        // Mark as visited
        grid[i][j] = '#';

        // Store position relative to the starting cell
        shape.add((i - x0) + "," + (j - y0));

        for (int[] dir : dirs) {
            dfs(grid, x0, y0, i + dir[0], j + dir[1],
                shape);
        }
    }

    static int countDistinctIslands(char[][] grid)
    {
        int rows = grid.length;
        int cols = grid[0].length;

        Set<ArrayList<String> > shapes = new HashSet<>();

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (grid[i][j] != 'L')
                    continue;

                ArrayList<String> shape = new ArrayList<>();
                dfs(grid, i, j, i, j, shape);
                shapes.add(shape);
            }
        }

        return shapes.size();
    }

    public static void main(String[] args)
    {

        int n = 4, m = 5;

        char[][] grid = { { 'L', 'W', 'W', 'L', 'W' },
                          { 'L', 'W', 'W', 'L', 'W' },
                          { 'W', 'W', 'W', 'L', 'L' },
                          { 'L', 'L', 'W', 'W', 'W' } };

        System.out.println(countDistinctIslands(grid));
    }
}
Python
# Four directions:
# left, up, right, down
dirs = [(0, -1), (-1, 0), (0, 1), (1, 0)]

# DFS to traverse an island and
# record its relative shape.


def dfs(grid, x0, y0, i, j, shape):
    rows = len(grid)
    cols = len(grid[0])

    if (i < 0 or i >= rows or j < 0 or j >= cols or grid[i][j] != 'L'):
        return

    # Mark current cell as visited.
    grid[i][j] = '#'

    # Store coordinates relative
    # to the starting cell.
    shape.append((i - x0, j - y0))

    for dx, dy in dirs:
        dfs(grid, x0, y0, i + dx, j + dy, shape)


def countDistinctIslands(grid):
    rows = len(grid)
    cols = len(grid[0])

    shapes = set()

    for i in range(rows):
        for j in range(cols):

            if grid[i][j] != 'L':
                continue

            shape = []

            dfs(grid, i, j, i, j, shape)

            shapes.add(tuple(shape))

    return len(shapes)


if __name__ == "__main__":
    n = 4
    m = 5

    grid = [['L', 'W', 'W', 'L', 'W'],
            ['L', 'W', 'W', 'L', 'W'],
            ['W', 'W', 'W', 'L', 'L'],
            ['L', 'L', 'W', 'W', 'W']]

    print(countDistinctIslands(grid))
C#
using System;
using System.Collections.Generic;

class GFG {
    static int[][] dirs
        = { new int[] { 0, -1 }, new int[] { -1, 0 },
            new int[] { 0, 1 }, new int[] { 1, 0 } };

    static void dfs(char[][] grid, int x0, int y0, int i,
                    int j, List<string> shape)
    {
        int rows = grid.Length, cols = grid[0].Length;

        if (i < 0 || i >= rows || j < 0 || j >= cols
            || grid[i][j] != 'L')
            return;

        // Mark as visited
        grid[i][j] = '#';

        // Store position relative to the starting cell
        shape.Add((i - x0) + "," + (j - y0));

        foreach(int[] dir in dirs)
        {
            dfs(grid, x0, y0, i + dir[0], j + dir[1],
                shape);
        }
    }

    static int countDistinctIslands(char[][] grid)
    {
        int rows = grid.Length;
        int cols = grid[0].Length;

        HashSet<string> shapes = new HashSet<string>();

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (grid[i][j] != 'L')
                    continue;

                List<string> shape = new List<string>();
                dfs(grid, i, j, i, j, shape);

                shapes.Add(string.Join("|", shape));
            }
        }

        return shapes.Count;
    }

    static void Main()
    {

        char[][] grid
            = { new char[] { 'L', 'W', 'W', 'L', 'W' },
                new char[] { 'L', 'W', 'W', 'L', 'W' },
                new char[] { 'W', 'W', 'W', 'L', 'L' },
                new char[] { 'L', 'L', 'W', 'W', 'W' } };

        Console.WriteLine(countDistinctIslands(grid));
    }
}
JavaScript
function dfs(grid, x0, y0, i, j, shape, dirs)
{
    var rows = grid.length;
    var cols = grid[0].length;

    if (i < 0 || i >= rows || j < 0 || j >= cols
        || grid[i][j] !== "L") {
        return;
    }

    // Mark the current cell as visited.
    grid[i][j] = "#";

    // Store coordinates relative to
    // the starting cell of the island.
    shape.push((i - x0) + "," + (j - y0));

    for (var k = 0; k < dirs.length; k++) {
        var dx = dirs[k][0];
        var dy = dirs[k][1];

        dfs(grid, x0, y0, i + dx, j + dy, shape, dirs);
    }
}

function countDistinctIslands(grid)
{

    // Four possible directions:
    // left, up, right, down
    var dirs = [ [ 0, -1 ], [ -1, 0 ], [ 0, 1 ], [ 1, 0 ] ];

    var rows = grid.length;
    var cols = grid[0].length;

    // Stores the normalized shape of each island.
    var shapes = {};

    for (var i = 0; i < rows; i++) {
        for (var j = 0; j < cols; j++) {

            if (grid[i][j] !== "L")
                continue;

            var shape = [];

            dfs(grid, i, j, i, j, shape, dirs);

            // Convert the shape into a unique string
            // representation and insert into the set.
            shapes[shape.join("|")] = true;
        }
    }

    return Object.keys(shapes).length;
}

// Driver Code

var grid = [
    [ "L", "W", "W", "L", "W" ],
    [ "L", "W", "W", "L", "W" ],
    [ "W", "W", "W", "L", "L" ], [ "L", "L", "W", "W", "W" ]
];

console.log(countDistinctIslands(grid));

Output
3
Comment