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] Number of Distinct Islands II 不同岛屿的个数之二的更多相关文章

  1. [LeetCode] 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 ...

  2. [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 ...

  3. 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 ...

  4. 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 ...

  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 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 用了第一种方式, ...

  8. 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 ...

  9. [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 ...

随机推荐

  1. SSRS: How to Display Checkbox on Report

    How to Display Checkbox on Report A textbox with Wingdings font type can be used to display a checkb ...

  2. Java基础笔记(1)----语言基础

    变量 变量:是内存中的一块存储空间,是存储数据的基本单元. 使用:先声明,后赋值,在使用. 声明:数据类型 + 变量名 = 值.(例:int a = 5:) 数据类型 分类:如图: 详解: Strin ...

  3. Java基础学习笔记十八 异常处理

    什么是异常?Java代码在运行时期发生的问题就是异常. 在Java中,把异常信息封装成了一个类.当出现了问题时,就会创建异常类对象并抛出异常相关的信息(如异常出现的位置.原因等). 异常的继承体系 在 ...

  4. 高级软件工程2017第5次作业—— 团队项目:需求改进&系统设计

    Deadline:2017-10-23(周一) 21:00pm 注:以下内容参考 集大作业 1.评分规则: 按时交 - 有分,检查的项目包括后文的四个方面 需求&原型改进 - 20分 系统设计 ...

  5. 听翁恺老师mooc笔记(10)--结构

    定义结构: 在程序里,如果想要表达一个数据就需要一个变量,而每个变量又都需要一个类型,之前学过C语言中有int.double.float.char等这些基础类型,还有指针.数组等.如果你要表达的数据比 ...

  6. Java课程设计报告——学生成绩管理系统

    一.需求分析 1.数据存储在数据库和文件中 2.分为"教师"模块和"学生"模块. 3.学生模块提供登陆功能,登陆成功后可查询数学.Java.体育成绩 (学生学号 ...

  7. Java Client/Server 基础知识

    Java的网络类库支持多种Internet协议,包括Telnet, FTP 和HTTP (WWW),与此相对应的Java网络类库的子类库为: Java.net  Java.net.ftp  Java. ...

  8. bzoj千题计划244:bzoj3730: 震波

    http://www.lydsy.com/JudgeOnline/problem.php?id=3730 点分树内对每个节点动态维护2颗线段树 线段树以距离为下标,城市的价值为权值 对于节点x的两棵线 ...

  9. CNN中的padding

    在使用TF搭建CNN的过程中,卷积的操作如下 convolution = tf.nn.conv2d(X, filters, strides=[1,2,2,1], padding="SAME& ...

  10. 从PRISM开始学WPF(三)Prism-Region?

    从PRISM开始学WPF(一)WPF? 从PRISM开始学WPF(二)Prism? 从PRISM开始学WPF(三)Prism-Region? 从PRISM开始学WPF(四)Prism-Module? ...