Skip to content

Commit ef2aefd

Browse files
Number of Distinct Islands II- Accepted
1 parent f3f8826 commit ef2aefd

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ My accepted leetcode solutions to some of the common interview problems.
101101
- [CloneGraph](problems/src/depth_first_search/CloneGraph.java) (Medium)
102102
- [Island Perimeter](problems/src/depth_first_search/IslandPerimeter.java) (Easy)
103103
- [Number of Distinct Islands](problems/src/depth_first_search/NumberOfDistinctIslands.java) (Medium)
104+
- [Number of Distinct Islands II](problems/src/depth_first_search/NumberOfDistinctIslandsII.java) (Hard)
104105

105106
#### [Design](problems/src/design)
106107

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package depth_first_search;
2+
3+
import java.util.*;
4+
import java.util.stream.Collectors;
5+
6+
/**
7+
* Created by gouthamvidyapradhan on 27/04/2018.
8+
* Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) connected
9+
* 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water.
10+
11+
Count the number of distinct islands. An island is considered to be the same as another if they have the same
12+
shape, or have the same shape after rotation (90, 180, or 270 degrees only) or reflection (left/right direction or
13+
up/down direction).
14+
15+
Example 1:
16+
11000
17+
10000
18+
00001
19+
00011
20+
Given the above grid map, return 1.
21+
22+
Notice that:
23+
11
24+
1
25+
and
26+
1
27+
11
28+
are considered same island shapes. Because if we make a 180 degrees clockwise rotation on the first island, then
29+
two islands will have the same shapes.
30+
Example 2:
31+
11100
32+
10001
33+
01001
34+
01110
35+
Given the above grid map, return 2.
36+
37+
Here are the two distinct islands:
38+
111
39+
1
40+
and
41+
1
42+
1
43+
44+
Notice that:
45+
111
46+
1
47+
and
48+
1
49+
111
50+
are considered same island shapes. Because if we flip the first array in the up/down direction, then they have the
51+
same shapes.
52+
Note: The length of each dimension in the given grid does not exceed 50.
53+
54+
Solution: General idea is to get the co-ordinates of each shape using dfs and rotate/reflect each point in a shape
55+
to transform each shape to a new possible shape (there are 8 possible shapes after rotation and reflection). Sort the
56+
new coordinates of each transformed shape and reduce each shape to a canonical key. Use a hash-set to count total
57+
number of such keys.
58+
59+
Some background on rotation and reflection:
60+
-------------------------------------------
61+
Rotate co-ordinates using formula [x′y′]=[[cosθ -sinθ], [sinθ cosθ]] [x y] where θ = {0, 90, 180, 270}
62+
There are 4 possible rotation points and for each rotation point obtain the reflection on each x and y axis.
63+
Rotation and reflection results in total of 8 points such as (x, y), (-x, y), (x, -y), (-x, -y),
64+
(y, x), (-y, x), (y, -x) and (-y, -x).
65+
66+
67+
68+
*/
69+
public class NumberOfDistinctIslandsII {
70+
private final int[] R = {0, 1, 0, -1};
71+
private final int[] C = {1, 0, -1, 0};
72+
private boolean[][] done;
73+
74+
class Point implements Comparable<Point>{
75+
int x; int y;
76+
Point(int x, int y){
77+
this.x = x;
78+
this.y = y;
79+
}
80+
81+
@Override
82+
public int compareTo(Point o) {
83+
if(this.x == o.x){
84+
return Integer.compare(this.y, o.y);
85+
} return Integer.compare(this.x, o.x);
86+
}
87+
}
88+
/**
89+
* Main method
90+
* @param args
91+
* @throws Exception
92+
*/
93+
public static void main(String[] args) throws Exception{
94+
int[][] grid = {{1,1,0,0,0}, {1,0,0,0,0}, {0,0,0,0,1}, {0,0,0,1,1}};
95+
System.out.println(new NumberOfDistinctIslandsII().numDistinctIslands2(grid));
96+
}
97+
98+
public int numDistinctIslands2(int[][] grid) {
99+
List<List<Point>> shapes = new ArrayList<>();
100+
done = new boolean[grid.length][grid[0].length];
101+
Set<String> islands = new HashSet<>();
102+
for(int i = 0; i < grid.length; i++){
103+
for(int j = 0; j < grid[0].length; j++){
104+
if(!done[i][j] && grid[i][j] == 1){
105+
List<Point> points = new ArrayList<>();
106+
dfs(i, j, grid, points);
107+
shapes.add(points);
108+
}
109+
}
110+
}
111+
for(List<Point> shape : shapes){
112+
List<List<Point>> eightShapes = rotateAndReflect(shape);
113+
islands.add(genKey(eightShapes));
114+
}
115+
return islands.size();
116+
}
117+
118+
/**
119+
* Generate a canonical key
120+
* @param eighShapes
121+
* @return
122+
*/
123+
private String genKey(List<List<Point>> eighShapes){
124+
List<String> keys = new ArrayList<>();
125+
for(List<Point> shape : eighShapes){
126+
Collections.sort(shape);
127+
Point first = shape.get(0);
128+
keys.add(shape.stream().map(s -> new Point(s.x - first.x, s.y - first.y))
129+
.map(p -> p.x + ":" + p.y).collect(Collectors.joining( "," )));
130+
}
131+
Collections.sort(keys);
132+
return keys.get(0);
133+
}
134+
135+
/**
136+
* Rotate and reflect a given shape to 8 possible shapes
137+
* @param shape
138+
* @return
139+
*/
140+
private List<List<Point>> rotateAndReflect(List<Point> shape){
141+
Map<Integer, List<Point>> map = new HashMap<>();
142+
for(int i = 0; i < 8; i ++){
143+
map.put(i, new ArrayList<>());
144+
}
145+
for(Point point : shape){
146+
map.get(0).add(new Point(point.x, point.y));
147+
map.get(1).add(new Point(-point.x, point.y));
148+
map.get(2).add(new Point(point.x, -point.y));
149+
map.get(3).add(new Point(-point.x, -point.y));
150+
map.get(4).add(new Point(point.y, point.x));
151+
map.get(5).add(new Point(-point.y, point.x));
152+
map.get(6).add(new Point(point.y, -point.x));
153+
map.get(7).add(new Point(-point.y, -point.x));
154+
}
155+
return new ArrayList<>(map.values());
156+
}
157+
158+
159+
private void dfs(int r, int c, int[][] grid, List<Point> points){
160+
done[r][c] = true;
161+
points.add(new Point(c, r));
162+
for(int i = 0; i < 4; i ++){
163+
int newR = r + R[i];
164+
int newC = c + C[i];
165+
if(newR >= 0 && newC >= 0 && newR < grid.length && newC < grid[0].length && grid[newR][newC] == 1 &&
166+
!done[newR][newC]){
167+
dfs(newR, newC, grid, points);
168+
}
169+
}
170+
}
171+
}

0 commit comments

Comments
 (0)