Given a non-empty 2D arraygridof 0's and 1's, an island is a group of1's (representing land) connected 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water.
Count the number of distinct islands. 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.
Example 1:
11000
11000
00011
00011
Given the above grid map, return1.
Example 2:
11011
10000
00001
11011
Given the above grid map, return3.
Notice that:
11
1
and
1
11
are considered different island shapes, because we do not consider reflection / rotation.
Note:The length of each dimension in the givengriddoes not exceed 50.
解法二:其实这个pattern,我们每次都得loop一遍所有找到得island来判断,这样比较低效。所以如果能生成一个unique的key的话,我们每次就只要去hashmap里看看,最后返回map的size就好了。那么怎么生成unique的key呢,其实,因为bfs的顺序是一样的从左上到右下,所以所有同款的island所包含的node加入到这个island的顺序是一样的。我们就用set of set来装。T:O(n*m), S:O(n * m)
class Solution {
int n = 0;
int m = 0;
public int numDistinctIslands(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0) {
return 0;
}
n = grid.length;
m = grid[0].length;
boolean[][] visited = new boolean[n][m];
Set<Set<Pair<Integer, Integer>>> islands = new HashSet<>();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 0 || visited[i][j]) {
continue;
}
Set<Pair<Integer, Integer>> nodesOfAIsland = new HashSet<>();
findIsland(i, j, grid, visited, nodesOfAIsland);
islands.add(nodesOfAIsland);
}
}
return islands.size();
}
int[] x = {0, 0, 1, -1};
int[] y = {1, -1, 0, 0};
private void findIsland(int i, int j, int[][] grid, boolean[][] visited, Set<Pair<Integer, Integer>> nodesOfAIsland) {
Queue<Integer> queue = new LinkedList<>();
queue.offer(i * m + j);
visited[i][j] = true;
while (!queue.isEmpty()) {
int cur = queue.poll();
int curi = cur / m;
int curj = cur % m;
nodesOfAIsland.add(new Pair<>(curi - i, curj - j));
for (int k = 0; k < 4; k++) {
int nexti = curi + x[k];
int nextj = curj + y[k];
if (inBound(nexti, nextj) && !visited[nexti][nextj] && grid[nexti][nextj] == 1) {
queue.offer(nexti * m + nextj);
visited[nexti][nextj] = true;
}
}
}
}
private boolean inBound(int i, int j) {
if (i < 0 || j < 0 || i >= n || j >= m) {
return false;
}
return true;
}
}
public int numDistinctIslands(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0) {
return 0;
}
int n = grid.length;
int m = grid[0].length;
// <cnt, List<pattern>>
Map<Integer, List<List<Integer>>> map = new HashMap<>();
int unique = 0;
boolean[][] visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 1 && !visited[i][j]) {
List<Integer> tmp = new ArrayList<>();
int cnt = bfs(grid, tmp, visited, i, j);
// 找到一个island就判断一下是否unique,是的话就++
if (isUnique(cnt, tmp, map, m)) {
unique++;
}
}
}
}
return unique;
}
int[] x = {0, 0, 1, -1};
int[] y = {1, -1, 0, 0};
// 经典bfs,边数island size边把island的pattern记到tmp里
private int bfs(int[][] grid, List<Integer> tmp, boolean[][] visited, int i, int j) {
int n = grid.length;
int m = grid[0].length;
Queue<Integer> queue = new LinkedList<>();
queue.offer(i * m + j);
visited[i][j] = true;
int cnt = 0;
while (!queue.isEmpty()) {
int cur = queue.poll();
int curi = cur / m;
int curj = cur % m;
cnt++;
tmp.add(cur);
for (int k = 0; k < 4; k++) {
int ni = curi + x[k];
int nj = curj + y[k];
if (ni >= 0 && ni < n && nj >= 0 && nj < m && !visited[ni][nj] && grid[ni][nj] == 1) {
queue.offer(ni * m + nj);
visited[ni][nj] = true;
}
}
}
return cnt;
}
// 判断同样size的island之间pattern有没有match
private boolean isUnique(int cnt, List<Integer> tmp, Map<Integer, List<List<Integer>>> map, int m) {
// 不同size的island是unique的
if (!map.containsKey(cnt)) {
map.put(cnt, new ArrayList<>());
map.get(cnt).add(new ArrayList<>(tmp));
return true;
}
List<List<Integer>> patterns = map.get(cnt);
for (List<Integer> pattern : patterns) {
if (isMatch(tmp, pattern, m)) {
return false;// 只要有一个match就证明不是unique的了
}
}
// 发现unique的记得加到map里
map.get(cnt).add(new ArrayList<>(tmp));
return true;
}
//判断两个pattern是否match
private boolean isMatch(List<Integer> tmp, List<Integer> pattern, int m) {
int diffi = pattern.get(0) / m - tmp.get(0) / m;
int diffj = pattern.get(0) % m - tmp.get(0) % m;
for (int i = 1; i < pattern.size(); i++) {
int curi = pattern.get(i) / m - tmp.get(i) / m;
int curj = pattern.get(i) % m - tmp.get(i) % m;
if (curi != diffi || curj != diffj) {
return false;
}
}
return true;
}