Find the number of distinct islands in a 2D matrix

Last Updated : 13 Oct, 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] 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 island, record the coordinates of its land cells relative to its starting cell.
  • Compare the resulting shape with all previously stored shapes.
  • If no matching shape exists, store it as a new distinct shape.
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 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] Set - O(n × m) Time and O(n × m) Space

We store island shapes in a set, which keeps only unique shapes.

Each island is represented using the relative coordinates of its cells with respect to its first cell. Therefore, islands with the same shape produce the same representation, regardless of their position in the grid.

Consider the grid[][]:

blobid2_1781703222
  • The island starting at (0, 0) has relative coordinates [(0, 0), (0, 1), (1, 0)]. Insert this shape into the set.
  • The island starting at (0, 3) has relative coordinates [(0, 0), (0, 1)]. Insert this shape into the set.
  • The island starting at (2, 4) has relative coordinates [(0, 0), (1, -1), (1, 0)]. Since this shape differs from the existing shapes, insert it into the set.
  • The island starting at (3, 0) has relative coordinates [(0, 0), (0, 1)]. This shape already exists, so do not count it again.

After traversing the entire grid, the set contains 3 distinct island shapes.

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', 'L', 'W', 'L', 'L'},
                                 {'L', 'W', 'W', 'W', 'W'},
                                 {'W', 'W', 'W', 'W', 'L'},
                                 {'L', 'L', 'W', 'L', 'L'}};

    cout << countDistinctIslands(grid);

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

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', 'L', 'W', 'L', 'L' },
                          { 'L', 'W', 'W', 'W', 'W' },
                          { 'W', 'W', 'W', 'W', 'L' },
                          { 'L', 'L', 'W', 'L', 'L' } };

        System.out.println(countDistinctIslands(grid));
    }
}
Python
def countDistinctIslands(grid):

    rows = len(grid)
    cols = len(grid[0])

    # Four directions:
    # left, up, right, down
    dirs = [(0, -1), (-1, 0), (0, 1), (1, 0)]

    # Store distinct island shapes
    shapes = set()

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

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

            shape = []

            # DFS stack
            stack = [(i, j)]

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

            while stack:

                x, y = stack.pop()

                # Store relative coordinates
                shape.append((x - i, y - j))

                for dx, dy in dirs:

                    nx = x + dx
                    ny = y + dy

                    if (0 <= nx < rows and
                        0 <= ny < cols and
                        grid[nx][ny] == 'L'):

                        grid[nx][ny] = '#'
                        stack.append((nx, ny))

            # Store unique island shape
            shapes.add(tuple(shape))

    return len(shapes)


if __name__ == "__main__":

    n = 4
    m = 5

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

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

class GFG
{
    // Four directions:
    // left, up, right, down
    static int[][] dirs =
    {
        new int[] { 0, -1 },
        new int[] { -1, 0 },
        new int[] { 0, 1 },
        new int[] { 1, 0 }
    };

    // DFS to traverse an island and
    // record its relative shape
    static void dfs(char[,] grid, int x0, int y0,
                    int i, int j, List<(int, int)> shape)
    {
        int rows = grid.GetLength(0);
        int cols = grid.GetLength(1);

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

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

        // Store relative coordinates
        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.GetLength(0);
        int cols = grid.GetLength(1);

        // Store distinct island shapes
        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<(int, int)> shape =
                    new List<(int, int)>();

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

                // Convert shape into a unique string
                string shapeKey = string.Join("|",
                    shape.ConvertAll(
                        p => p.Item1 + "," + p.Item2));

                // Store unique shape
                shapes.Add(shapeKey);
            }
        }

        return shapes.Count;
    }

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

        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", "L", "W", "L", "L" ],
    [ "L", "W", "W", "W", "W" ],
    [ "W", "W", "W", "W", "L" ], 
    [ "L", "L", "W", "L", "L" ]
];

console.log(countDistinctIslands(grid));

Output
3
Comment