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. 【Linux命令】at、crontab定时任务

    crontab定时任务(周期性) 一.简介 通过crontab命令可以在固定的间隔执行系统指令或shell脚本 二.crontab配置文件: Linux下的任务调度分为两类:系统任务调度和用户任务调度 ...

  2. MySQL管理工具 -- MySQL Workbench

    管理MySQL,可以使用可视化图形界面MySQL Workbench.MySQL Workbench是一个图形客户端,可以用可视化的方式查询.创建和修改数据库表.它对MySQL的操作仍然是发送SQL语 ...

  3. openssl编译安装

    最新版本可以在这个网站下载: https://www.openssl.org/source/ wget https://www.openssl.org/source/openssl-1.1.1c.ta ...

  4. lego loam 跑镭神32线激光雷达

    师弟反应镭神32线激光雷达(32C)录制的数据包不能跑lego loam,这里就总结一下. 首先lego loam默认的接受的topic name是velodyne_points,点云的frame_i ...

  5. jersey常用注解解释 JAX-RS常用注解:

    jersey常用注解解释: Annotation 作用 说明 @GET 查询请求 相当于数据库的查询数据操作 @PUT 更新请求 相当于数据库的更新数据操作 @POST 插入请求 相当于数据库的插入数 ...

  6. python3之利用字典和列表实现城市多级菜单

    利用字典和列表实现城市多级菜单 #coding:utf-8 #利用字典和列表实现城市多级菜单 addrIndex = {":"福建"} addrDict = {" ...

  7. 【设计模式】Composite

    目录 前言 安卓View的实现 View Beyond setContentView setContentView做了什么事情? 如何将xml文件变成对象的? 小结 View的绘制流程 三个流程 三个 ...

  8. 前端开发JS——数组

    25.数组 1)声明数组: ①构造函数创建数组 var arr = new Array(); console.log(arr):        //[]   var arr = new Array(2 ...

  9. electron——ipcMain模块、ipcRenderer模块

    ipcMain 从 主进程 到 渲染进程 的异步通信. ipcMain模块是EventEmitter类的一个实例. 当在主进程中使用时,它处理从渲染器进程(网页)发送出来的异步和同步信息. 从渲染器进 ...

  10. SAP MM Purchase Order History Category

    SAP MM Purchase Order History Category 1) ,These are different categories of PO history which is con ...