[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) 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
类似题目:
参考资料:
https://leetcode.com/problems/number-of-distinct-islands-ii/
https://leetcode.com/problems/number-of-distinct-islands-ii/discuss/231300/C%2B%2B-BFSDFS
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] 711. Number of Distinct Islands II 不同岛屿的个数之二的更多相关文章
- [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 ...
- [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 ...
- 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 ...
- [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 ...
- [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 ...
- [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 ...
- [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 ...
- 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 用了第一种方式, ...
- 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 ...
随机推荐
- UVA 291 The House Of Santa Claus DFS
题目: In your childhood you most likely had to solve the riddle of the house of Santa Claus. Do you re ...
- LibLog 类库 分析
前期思考: Microsoft.Logging 是否可用? 是否需要提供默认的 Logger 实现? 不需要.1,用户自己开启日志功能,设置开启属性,即可打印出相应的日志. LibLog 类库分析: ...
- webstorm关闭烦人的eslint语法检查
使用了eslint语法检查之后发现JS代码里面处处是红线,通过右键菜单中的fix eslint problems选项又会发现页面代码的格式被eslint换行得不分青红皂白,索性关闭exlint语法检查 ...
- WPF DataGrid使用DataTable为数据源,添加CheckBox列使用Delete删除行的方法
首先将CanUserDeleteRows设置为False, 其次是设置KeyUp事件 并自定义DataGrid.Columns修改如下 <DataGrid x:Name="DG&quo ...
- A Pattern Language for Parallel Programming
The pattern language is organized into four design spaces. Generally one starts at the top in the F ...
- VS2019打开旧项目导致引用失效的解决方案
用VS2019打开VS2015创建的MVC项目时所有引用全部失效: 解决方案: 打开项目的csproj文件,删除 Target节点,在重新打开项目. <Target Name="Ens ...
- The underlying connection was closed: An unexpected error occurred on a send
操作系统是Windows Server 2003 x64 SP2,使用Framework 4.0,在使用WebClient访问某些特定的HTTPS站点时,会引发异常: Unhandled Except ...
- 开源工作流引擎 Workflow Core 的研究和使用教程
目录 开源工作流引擎 Workflow Core 的研究和使用教程 一,工作流对象和使用前说明 二,IStepBuilder 节点 三,工作流节点的逻辑和操作 容器操作 普通节点 事件 条件体和循环体 ...
- centos 7 防火墙相关操作
centos 7 防火墙相关操作 CentOS 7.0默认使用的是firewall作为防火墙,这里改为iptables防火墙. 1.关闭firewall: systemctl stop firewal ...
- wsl下安装并运行Kafka
0.引言 kafka是一个高性能分布式的MQ,今天我们就来玩玩 1.安装 wget http://mirrors.tuna.tsinghua.edu.cn/apache/kafka/2.3.0/kaf ...