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.
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.
[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>usingnamespacestd;voiddfs(vector<vector<char>>&grid,intbaseRow,intbaseCol,introw,intcol,vector<pair<int,int>>&shape){intn=grid.size();intm=grid[0].size();if(row<0||row>=n||col<0||col>=m||grid[row][col]!='L'){return;}// Mark current cell as visitedgrid[row][col]='#';// Store relative coordinatesshape.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);}intcountDistinctIslands(vector<vector<char>>&grid){intn=grid.size();intm=grid[0].size();// Stores all distinct island shapesvector<vector<pair<int,int>>>distinctShapes;for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(grid[i][j]=='L'){vector<pair<int,int>>shape;// Find shape of current islanddfs(grid,i,j,i,j,shape);boolfound=false;// Compare with previously found shapesfor(auto&prevShape:distinctShapes){if(prevShape==shape){found=true;break;}}// Store shape if it is uniqueif(!found){distinctShapes.push_back(shape);}}}}returndistinctShapes.size();}// Driver Codeintmain(){intn=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);return0;}
Java
importjava.util.ArrayList;classGFG{staticvoiddfs(char[][]grid,intbaseRow,intbaseCol,introw,intcol,ArrayList<String>shape){intn=grid.length;intm=grid[0].length;if(row<0||row>=n||col<0||col>=m||grid[row][col]!='L'){return;}// Mark current cell as visitedgrid[row][col]='#';// Store relative coordinatesshape.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);}staticintcountDistinctIslands(char[][]grid){intn=grid.length;intm=grid[0].length;// Stores all distinct island shapesArrayList<ArrayList<String>>distinctShapes=newArrayList<>();for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(grid[i][j]=='L'){ArrayList<String>shape=newArrayList<>();// Find shape of current islanddfs(grid,i,j,i,j,shape);booleanfound=false;// Compare with previously found shapesfor(ArrayList<String>prevShape:distinctShapes){if(prevShape.equals(shape)){found=true;break;}}// Store shape if it is uniqueif(!found){distinctShapes.add(shape);}}}}returndistinctShapes.size();}publicstaticvoidmain(String[]args){intn=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
defdfs(grid,baseRow,baseCol,row,col,shape):n=len(grid)m=len(grid[0])ifrow<0orrow>=norcol<0orcol>=morgrid[row][col]!='L':return# Mark current cell as visitedgrid[row][col]='#'# Store relative coordinatesshape.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)defcountDistinctIslands(grid):n=len(grid)m=len(grid[0])# Stores all distinct island shapesdistinctShapes=[]foriinrange(n):forjinrange(m):ifgrid[i][j]=='L':shape=[]# Find shape of current islanddfs(grid,i,j,i,j,shape)found=False# Compare with previously found shapesforprevShapeindistinctShapes:ifprevShape==shape:found=Truebreak# Store shape if it is uniqueifnotfound:distinctShapes.append(shape)returnlen(distinctShapes)if__name__=="__main__":n,m=4,5grid=[['L','W','W','L','W'],['L','W','W','L','W'],['W','W','W','L','L'],['L','L','W','W','W']]print(countDistinctIslands(grid))
C#
usingSystem;usingSystem.Collections.Generic;classGFG{staticvoiddfs(char[,]grid,intbaseRow,intbaseCol,introw,intcol,List<string>shape){intn=grid.GetLength(0);intm=grid.GetLength(1);if(row<0||row>=n||col<0||col>=m||grid[row,col]!='L'){return;}// Mark current cell as visitedgrid[row,col]='#';// Store relative coordinatesshape.Add((row-baseRow)+","+(col-baseCol));// 4-direction DFSdfs(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);}staticintcountDistinctIslands(char[,]grid){intn=grid.GetLength(0);intm=grid.GetLength(1);// Stores all distinct island shapesList<List<string>>distinctShapes=newList<List<string>>();for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(grid[i,j]=='L'){List<string>shape=newList<string>();// Find shape of current islanddfs(grid,i,j,i,j,shape);boolfound=false;// Compare with previously stored shapesforeach(List<string>prevShapeindistinctShapes){if(prevShape.Count!=shape.Count){continue;}boolsame=true;for(intk=0;k<shape.Count;k++){if(prevShape[k]!=shape[k]){same=false;break;}}if(same){found=true;break;}}// Store shape if it is uniqueif(!found){distinctShapes.Add(shape);}}}}returndistinctShapes.Count;}staticvoidMain(){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
functiondfs(grid,baseRow,baseCol,row,col,shape){letn=grid.length;letm=grid[0].length;if(row<0||row>=n||col<0||col>=m||grid[row][col]!=="L"){return;}// Mark current cell as visitedgrid[row][col]="#";// Store relative coordinatesshape.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);}functioncountDistinctIslands(grid){letn=grid.length;letm=grid[0].length;// Stores all distinct island shapesletdistinctShapes=[];for(leti=0;i<n;i++){for(letj=0;j<m;j++){if(grid[i][j]==="L"){letshape=[];// Find shape of current islanddfs(grid,i,j,i,j,shape);letfound=false;// Compare with previously found shapesfor(letprevShapeofdistinctShapes){if(JSON.stringify(prevShape)===JSON.stringify(shape)){found=true;break;}}// Store shape if it is uniqueif(!found){distinctShapes.push(shape);}}}}returndistinctShapes.length;}// driver codeletn=4,m=5;letgrid=[["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>usingnamespacestd;vector<vector<int>>dirs={{0,-1},{-1,0},{0,1},{1,0}};voiddfs(vector<vector<char>>&grid,intx0,inty0,inti,intj,vector<pair<int,int>>&shape){introws=grid.size(),cols=grid[0].size();if(i<0||i>=rows||j<0||j>=cols||grid[i][j]!='L')return;// Mark as visitedgrid[i][j]='#';// Store position relative to the starting cellshape.push_back({i-x0,j-y0});for(auto&dir:dirs){dfs(grid,x0,y0,i+dir[0],j+dir[1],shape);}}intcountDistinctIslands(vector<vector<char>>&grid){introws=grid.size();intcols=grid[0].size();set<vector<pair<int,int>>>shapes;for(inti=0;i<rows;i++){for(intj=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 Codeintmain(){intn=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);return0;}
Java
importjava.util.ArrayList;importjava.util.Set;importjava.util.HashSet;classGFG{staticint[][]dirs={{0,-1},{-1,0},{0,1},{1,0}};staticvoiddfs(char[][]grid,intx0,inty0,inti,intj,ArrayList<String>shape){introws=grid.length,cols=grid[0].length;if(i<0||i>=rows||j<0||j>=cols||grid[i][j]!='L')return;// Mark as visitedgrid[i][j]='#';// Store position relative to the starting cellshape.add((i-x0)+","+(j-y0));for(int[]dir:dirs){dfs(grid,x0,y0,i+dir[0],j+dir[1],shape);}}staticintcountDistinctIslands(char[][]grid){introws=grid.length;intcols=grid[0].length;Set<ArrayList<String>>shapes=newHashSet<>();for(inti=0;i<rows;i++){for(intj=0;j<cols;j++){if(grid[i][j]!='L')continue;ArrayList<String>shape=newArrayList<>();dfs(grid,i,j,i,j,shape);shapes.add(shape);}}returnshapes.size();}publicstaticvoidmain(String[]args){intn=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, downdirs=[(0,-1),(-1,0),(0,1),(1,0)]# DFS to traverse an island and# record its relative shape.defdfs(grid,x0,y0,i,j,shape):rows=len(grid)cols=len(grid[0])if(i<0ori>=rowsorj<0orj>=colsorgrid[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))fordx,dyindirs:dfs(grid,x0,y0,i+dx,j+dy,shape)defcountDistinctIslands(grid):rows=len(grid)cols=len(grid[0])shapes=set()foriinrange(rows):forjinrange(cols):ifgrid[i][j]!='L':continueshape=[]dfs(grid,i,j,i,j,shape)shapes.add(tuple(shape))returnlen(shapes)if__name__=="__main__":n=4m=5grid=[['L','W','W','L','W'],['L','W','W','L','W'],['W','W','W','L','L'],['L','L','W','W','W']]print(countDistinctIslands(grid))
C#
usingSystem;usingSystem.Collections.Generic;classGFG{staticint[][]dirs={newint[]{0,-1},newint[]{-1,0},newint[]{0,1},newint[]{1,0}};staticvoiddfs(char[][]grid,intx0,inty0,inti,intj,List<string>shape){introws=grid.Length,cols=grid[0].Length;if(i<0||i>=rows||j<0||j>=cols||grid[i][j]!='L')return;// Mark as visitedgrid[i][j]='#';// Store position relative to the starting cellshape.Add((i-x0)+","+(j-y0));foreach(int[]dirindirs){dfs(grid,x0,y0,i+dir[0],j+dir[1],shape);}}staticintcountDistinctIslands(char[][]grid){introws=grid.Length;intcols=grid[0].Length;HashSet<string>shapes=newHashSet<string>();for(inti=0;i<rows;i++){for(intj=0;j<cols;j++){if(grid[i][j]!='L')continue;List<string>shape=newList<string>();dfs(grid,i,j,i,j,shape);shapes.Add(string.Join("|",shape));}}returnshapes.Count;}staticvoidMain(){char[][]grid={newchar[]{'L','W','W','L','W'},newchar[]{'L','W','W','L','W'},newchar[]{'W','W','W','L','L'},newchar[]{'L','L','W','W','W'}};Console.WriteLine(countDistinctIslands(grid));}}
JavaScript
functiondfs(grid,x0,y0,i,j,shape,dirs){varrows=grid.length;varcols=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(vark=0;k<dirs.length;k++){vardx=dirs[k][0];vardy=dirs[k][1];dfs(grid,x0,y0,i+dx,j+dy,shape,dirs);}}functioncountDistinctIslands(grid){// Four possible directions:// left, up, right, downvardirs=[[0,-1],[-1,0],[0,1],[1,0]];varrows=grid.length;varcols=grid[0].length;// Stores the normalized shape of each island.varshapes={};for(vari=0;i<rows;i++){for(varj=0;j<cols;j++){if(grid[i][j]!=="L")continue;varshape=[];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;}}returnObject.keys(shapes).length;}// Driver Codevargrid=[["L","W","W","L","W"],["L","W","W","L","W"],["W","W","W","L","L"],["L","L","W","W","W"]];console.log(countDistinctIslands(grid));