Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1'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 they have the same shape, or have the same shape after rotation (90, 180, or 270 degrees only) or reflection (left/right direction or up/down direction).

Example 1:

11000
10000
00001
00011

Given the above grid map, return 1.

Notice that:

11
1

and

 1
11

are considered same island shapes. Because if we make a 180 degrees clockwise rotation on the first island, then two islands will have the same shapes.

Example 2:

11100
10001
01001
01110

Given the above grid map, return 2.

Here are the two distinct islands:

111
1

and

1
1

Notice that:

111
1

and

1
111

are considered same island shapes. Because if we flip the first array in the up/down direction, then they have the same shapes.

Note: The length of each dimension in the given grid does not exceed 50.

这道题是之前那道 Number of Distinct Islands 的拓展,之前那道题定义的相同的岛屿必须是形状完全相同的,而这里岛屿则可以进行 90 度旋转,或者是水平竖直方向的镜面对称,这样就极大的增加了难度,因为在判断两个形状是否属于一个岛屿的时候,要考虑各种各样的情况,十分的复杂。这道题最大的难点也就是在于如何对同一种岛屿形状进行建模,使得其所有翻转或者对称的岛屿形状可以归属到同一类中。在之前那道 Number of Distinct Islands 中,由于是有平移操作,使用的 trick 是利用相对位移保持不变的特性来确定同一种同一种岛屿形状的,在这道题中显然不适用了,因为这里各种变换会破坏相对位移。那该怎么办呢?比如现在有几个长度相同的数组,是乱序的,怎么才能知道这些数组是否可以通过排序变成相同的数组,则最简单的方法就是对所有的数组进行排序,排序后若相同,则表示属于同一类,那么这个排序后的数组其实就可以代表所有同一种数组。借鉴这种思路,其实要做的就是找到一种建模方式,将所有属于同一类的岛屿形状都转为其唯一的结构,然后放到一个有去处重复功能的集合中,最后集合中元素的个数即为不同岛屿的个数。

大体思路有了,再来看具体该如何实施。首先还是要找出每个单独的小岛,即找出所有相连的1,这跟之前的题目的做法相同,可以使用 DFS 或者 BFS 来找,这里先使用 DFS 来做。方法是遍历 grid 数组,当遇到为1的位置,说明遇到小岛了,对该位置调用递归函数,将和其相连的所有位置都存入到 shape 数组中。递归数组结束后,就有了该小岛所有位置的坐标,现在就要对其进行转换,或者叫 normalize,目的是变换成同一种岛屿形状的唯一表示。对于每一个坐标位置,其实总共有8种变换可能,x和y都可以分别变为相反数,且也可以同时变为相反数,再加上其本身,这就4种了。同时,上面的每一种情况都可以交换x和y的位置,这样总共就有8中变换方法,每一种情况都要考虑,所以使用8个大小相同的数组来保存各自所有的点。对于每一种形状,都对其所有的点进行排序,然后将每个点的绝对坐标变为相对坐标,即每个点都减去排序后第一个点的坐标,最后再对这8个形状排个序。这样一顿操作猛如虎之后,只要是属于同一个岛屿的形状,最后都会得到一模一样的8个形状数组,为了简单起见,只选取第一个形状形状当作这同一种岛屿的模型代表,并将其加入那个可以去重复的集合中即可,参见代码如下:

解法一:

class Solution {
public:
int numDistinctIslands2(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[].size();
set<vector<pair<int, int>>> st;
for (int i = ; i < m; ++i) {
for (int j = ; j < n; ++j) {
if (grid[i][j]) {
vector<pair<int, int>> shape;
helper(grid, i, j, shape);
st.insert(normalize(shape));
}
}
}
return st.size();
}
void helper(vector<vector<int>>& grid, int x, int y, vector<pair<int, int>>& shape) {
if (x < || x >= grid.size() || y < || y >= grid[].size()) return;
if (grid[x][y] == ) return;
grid[x][y] = ;
shape.push_back({x, y});
helper(grid, x + , y, shape);
helper(grid, x - , y, shape);
helper(grid, x, y + , shape);
helper(grid, x, y - , shape);
}
vector<pair<int, int>> normalize(vector<pair<int, int>>& shape) {
vector<vector<pair<int, int>>> shapes();
for (auto &a : shape) {
int x = a.first, y = a.second;
shapes[].push_back({x, y});
shapes[].push_back({x, -y});
shapes[].push_back({-x, y});
shapes[].push_back({-x, -y});
shapes[].push_back({y, x});
shapes[].push_back({y, -x});
shapes[].push_back({-y, x});
shapes[].push_back({-y, -x});
}
for (auto &a : shapes) {
sort(a.begin(), a.end());
for (int i = (int)shape.size() - ; i >= ; --i) {
a[i].first -= a[].first;
a[i].second -= a[].second;
}
}
sort(shapes.begin(), shapes.end());
return shapes[];
}
};

下面这种写法是 BFS 形式的,大体思路相同,就是在找每个岛屿的时候使用的是迭代的写法,找出了每个岛屿位置集合 shape 之后,进行 normalize 操作跟上面完全相同,最后还是看去重复集合中元素的个数即可,参见代码如下:

解法二:

class Solution {
public:
int numDistinctIslands2(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[].size();
set<vector<pair<int, int>>> st;
for (int i = ; i < m; ++i) {
for (int j = ; j < n; ++j) {
if (grid[i][j] == ) continue;
grid[i][j] = ;
vector<pair<int, int>> shape{{i, j}};
int i = ;
while (i < shape.size()) {
auto t = shape[i++];
int x = t.first, y = t.second;
if (x > && grid[x - ][y] != ) {
grid[x - ][y] = ;
shape.push_back({x - , y});
}
if (x + < m && grid[x + ][y] != ) {
grid[x + ][y] = ;
shape.push_back({x + , y});
}
if (y > && grid[x][y - ] != ) {
grid[x][y - ] = ;
shape.push_back({x, y - });
}
if (y + < n && grid[x][y + ] != ) {
grid[x][y + ] = ;
shape.push_back({x, y + });
}
}
st.insert(normalize(shape));
}
}
return st.size();
}
vector<pair<int, int>> normalize(vector<pair<int, int>>& shape) {
vector<vector<pair<int, int>>> shapes();
for (auto &a : shape) {
int x = a.first, y = a.second;
shapes[].push_back({x, y});
shapes[].push_back({x, -y});
shapes[].push_back({-x, y});
shapes[].push_back({-x, -y});
shapes[].push_back({y, x});
shapes[].push_back({y, -x});
shapes[].push_back({-y, x});
shapes[].push_back({-y, -x});
}
for (auto &a : shapes) {
sort(a.begin(), a.end());
for (int i = (int)shape.size() - ; i >= ; --i) {
a[i].first -= a[].first;
a[i].second -= a[].second;
}
}
sort(shapes.begin(), shapes.end());
return shapes[];
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/711

类似题目:

Number of Distinct Islands

参考资料:

https://leetcode.com/problems/number-of-distinct-islands-ii/

https://leetcode.com/problems/number-of-distinct-islands-ii/discuss/231300/C%2B%2B-BFSDFS

https://leetcode.com/problems/number-of-distinct-islands-ii/discuss/108794/Consise-C%2B%2B-solution-using-DFS-%2Bsorting-to-find-canonical-representation-for-each-island

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] 711. Number of Distinct Islands II 不同岛屿的个数之二的更多相关文章

  1. [LeetCode] Number of Distinct Islands II 不同岛屿的个数之二

    Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...

  2. [LeetCode] 711. Number of Distinct Islands II_hard tag: DFS

    Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...

  3. LC 711. Number of Distinct Islands II

    Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...

  4. [LeetCode] 694. Number of Distinct Islands 不同岛屿的个数

    Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...

  5. [leetcode]694. Number of Distinct Islands你究竟有几个异小岛?

    Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...

  6. [LeetCode] 694. Number of Distinct Islands

    Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...

  7. [LeetCode] Number of Distinct Islands 不同岛屿的个数

    Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...

  8. leetcode 200. Number of Islands 、694 Number of Distinct Islands 、695. Max Area of Island 、130. Surrounded Regions

    两种方式处理已经访问过的节点:一种是用visited存储已经访问过的1:另一种是通过改变原始数值的值,比如将1改成-1,这样小于等于0的都会停止. Number of Islands 用了第一种方式, ...

  9. LeetCode - Number of Distinct Islands

    Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...

随机推荐

  1. LeetCode 133:克隆图 Clone Graph

    题目: 给定无向连通图中一个节点的引用,返回该图的深拷贝(克隆).图中的每个节点都包含它的值 val(Int) 和其邻居的列表(list[Node]). Given a reference of a ...

  2. 【shell脚本】检查内存使用情况===chenkMen.sh

    检查内存使用情况,当内存可使用等于100时,释放缓存 [root@localhost thy]# cat checkMem.sh #!/bin/bash #防止内存溢出问题 used=`free -m ...

  3. Vue.js 源码分析(二十一) 指令篇 v-pre指令详解

    该指令会跳过所在元素和它的子元素的编译过程,也就是把这个节点及其子节点当作一个静态节点来处理,例如: <!DOCTYPE html> <html lang="en" ...

  4. C#中窗口关闭时没有取消事件订阅导致事件重复执行的解决方法

    场景 C#中委托与事件的使用-以Winform中跨窗体传值为例: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/100150700 ...

  5. 解决:500 Internal Privoxy Error

    500 Internal Privoxy Error Privoxy encountered an error while processing your request: Could not loa ...

  6. Python-函数参数类型及排序问题

    Python中函数的参数问题有点复杂,主要是因为参数类型问题导致的情况比较多,下面来分析一下. 参数类型:缺省参数,关键字参数,不定长位置参数,不定长关键字参数. 其实总共可以分为    位置参数和关 ...

  7. Python脚本1

    [轮子]P123. 求最大约数,并鉴别是否为素数

  8. JavaScript 数据类型转换表

    下表显示了将不同的JavaScript值转换为Number,String和Boolean的结果: 原始值 转换为Number 转换为String 转换为Boolean false 0 "fa ...

  9. 学习shiro第三天

    今天比较晚,所以只看了shiro的认证策略Authentication Strategy,下面讲讲shiro的三种认证策略. 1.AtLeastOneSuccessfulStrategy:这个是shi ...

  10. webpack4 css modules

    demo 代码点此,webpack4 中通过 css-loader 开启 css 模块化, 开始前先做点准备工作. 不了解 css 模块化的,可以前往查看github_css_modules. ##准 ...