[LeetCode] 305. Number of Islands II 岛屿的数量之二
A 2d grid map of m
rows and n
columns is initially filled with water. We may perform an addLand operation which turns the water at position (row, col) into a land. Given a list of positions to operate, count the number of islands after each addLand operation. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Example:
- Input: m = 3, n = 3, positions = [[0,0], [0,1], [1,2], [2,1]]
- Output: [1,1,2,3]
Explanation:
Initially, the 2d grid grid
is filled with water. (Assume 0 represents water and 1 represents land).
- 0 0 0
- 0 0 0
- 0 0 0
Operation 1: addLand(0, 0) turns the water at grid[0][0] into a land.
- 1 0 0
- 0 0 0 Number of islands = 1
- 0 0 0
Operation 2: addLand(0, 1) turns the water at grid[0][1] into a land.
- 1 1 0
- 0 0 0 Number of islands = 1
- 0 0 0
Operation 3: addLand(1, 2) turns the water at grid[1][2] into a land.
- 1 1 0
- 0 0 1 Number of islands = 2
- 0 0 0
Operation 4: addLand(2, 1) turns the water at grid[2][1] into a land.
- 1 1 0
- 0 0 1 Number of islands = 3
- 0 1 0
Follow up:
Can you do it in time complexity O(k log mn), where k is the length of the positions
?
这道题是之前那道 Number of Islands 的拓展,难度增加了不少,因为这次是一个点一个点的增加,每增加一个点,都要统一一下现在总共的岛屿个数,最开始初始化时没有陆地,如下:
0 0 0
0 0 0
0 0 0
假如在(0, 0)的位置增加一个陆地,那么此时岛屿数量为1:
1 0 0
0 0 0
0 0 0
假如再在(0, 2)的位置增加一个陆地,那么此时岛屿数量为2:
1 0 1
0 0 0
0 0 0
假如再在(0, 1)的位置增加一个陆地,那么此时岛屿数量却又变为1:
1 1 1
0 0 0
0 0 0
假如再在(1, 1)的位置增加一个陆地,那么此时岛屿数量仍为1:
1 1 1
0 1 0
0 0 0
为了解决这种陆地之间会合并的情况,最好能够将每个陆地都标记出其属于哪个岛屿,这样就会方便统计岛屿个数。这种群组类问题,很适合使用联合查找 Union Find 来做,又叫并查集 Disjoint Set,LeetCode 中使用这种解法的题目还不少呢,比如 Friend Circles,Graph Valid Tree,Redundant Connection II 等等。一般来说,UF 算法的思路是每个个体先初始化为不同的群组,然后遍历有关联的两个个体,如果发现其 getRoot 函数的返回值不同,则手动将二者加入一个群组,然后总群组数自减1。这里就要分别说一下 root 数组,和 getRoot 函数。两个同群组的个体,通过 getRoot 函数一定会返回相同的值,但是其在 root 数组中的值不一定相同,可以类比成 getRoot 函数返回的是祖先,如果两个人的祖先相同,那么其是属于一个家族的(这里不是指人类共同的祖先哈)。root 可以用数组或者 HashMap 来表示,如果个体是数字的话,那么数组就 OK,如果个体是字符串的话,可能就需要用 HashMap 了。root 数组的初始化可以有两种,可以均初始化为 -1,或者都初始化为不同的数字,博主一般喜欢初始化为不同的数字。getRoot 函数的写法也可用递归或者迭代的方式,可参见博主之前的帖子 Redundant Connection II 中的讨论部分。这么一说感觉 UF 算法的东西还蛮多的,啥时候博主写个 UF 总结贴吧。
那么具体来看这道题吧,此题跟经典的 UF 使用场景有一点点的区别,因为一般的场景中两个个体之间只有两种关系,属于一个群组或者不属于同一个群组,而这道题里面由于 water 的存在,就多了一种情况,只需要事先检测一下当前位置是不是岛屿就行了,总之问题不大。一般来说 root 数组都是使用一维数组,方便一些,那么这里就可以将二维数组 encode 为一维的,于是需要一个长度为 m*n 的一维数组来标记各个位置属于哪个岛屿,假设每个位置都是一个单独岛屿,岛屿编号可以用其坐标位置表示,但是初始化时将其都赋为 -1,这样方便知道哪些位置尚未变成岛屿。然后开始遍历陆地数组,若某个岛屿位置编码的 root 值不为 -1,说明这是一个重复出现的位置,不需要重新计算了,直接将 cnt 加入结果 res 中。否则将其岛屿编号设置为其坐标位置,然后岛屿计数加1,此时开始遍历其上下左右的位置,遇到越界或者岛屿标号为 -1 的情况直接跳过,现在知道初始化为 -1 的好处了吧,遇到是 water 的地方直接跳过。否则用 getRoot 来查找邻居位置的岛屿编号,同时也用 getRoot 来查找当前点的编号,这一步就是经典的 UF 算法的操作了,因为当前这两个 land 是相邻的,它们是属于一个岛屿,所以其 getRoot 函数的返回值 suppose 应该是相等的,但是如果返回值不同,说明需要合并岛屿,将两个返回值建立关联,并将岛屿计数 cnt 减1。当遍历完当前点的所有邻居时,该合并的都合并完了,将此时的岛屿计数 cnt 存入结果中,参见代码如下:
- class Solution {
- public:
- vector<int> numIslands2(int m, int n, vector<vector<int>>& positions) {
- vector<int> res;
- int cnt = ;
- vector<int> roots(m * n, -);
- vector<vector<int>> dirs{{, -}, {-, }, {, }, {, }};
- for (auto &pos : positions) {
- int id = n * pos[] + pos[];
- if (roots[id] != -) {
- res.push_back(cnt);
- continue;
- }
- roots[id] = id;
- ++cnt;
- for (auto dir : dirs) {
- int x = pos[] + dir[], y = pos[] + dir[], cur_id = n * x + y;
- if (x < || x >= m || y < || y >= n || roots[cur_id] == -) continue;
- int p = findRoot(roots, cur_id), q = findRoot(roots, id);
- if (p != q) {
- roots[p] = q;
- --cnt;
- }
- }
- res.push_back(cnt);
- }
- return res;
- }
- int findRoot(vector<int>& roots, int id) {
- return (id == roots[id]) ? id : findRoot(roots, roots[id]);
- }
- };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/305
类似题目:
参考资料:
https://leetcode.com/problems/number-of-islands-ii/
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] 305. Number of Islands II 岛屿的数量之二的更多相关文章
- [LeetCode] 305. Number of Islands II 岛屿的数量 II
A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand oper ...
- [LeetCode] Number of Islands II 岛屿的数量之二
A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand oper ...
- LeetCode 305. Number of Islands II
原题链接在这里:https://leetcode.com/problems/number-of-islands-ii/ 题目: A 2d grid map of m rows and n column ...
- 305. Number of Islands II
题目: A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand ...
- [LeetCode] 200. Number of Islands 岛屿的数量
Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surro ...
- 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 用了第一种方式, ...
- [Swift]LeetCode305. 岛屿的个数 II $ Number of Islands II
A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand oper ...
- Leetcode: Number of Islands II && Summary of Union Find
A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand oper ...
- [leetcode]200. Number of Islands岛屿个数
Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surro ...
随机推荐
- js生成条形码
生成条形码 <body> <div> <img id="ma"/> </div> </body> </html&g ...
- cmake打印shell
cmake链接库失败时,可通过打印路径下对应的lib来定位问题 execute_process(COMMAND ls -lt ${CMAKE_CURRENT_SOURCE_DIR}/lib #执行sh ...
- python asyncio 关闭task
import asyncio import time async def get_html(sleep_times): print("waiting") await asyncio ...
- Django学习笔记(19)——BBS+Blog项目开发(3)细节知识点补充
本文将BBS+Blog项目开发中所需要的细节知识点进行补充,其中内容包括KindEditor编辑器的使用,BeautifulSoup 模块及其防XSS攻击,Django中admin管理工具的使用,me ...
- JSTL+EL表达式+JSP自定义框架案例
不会框架不要紧,我带你自定义框架 前言:这标题说的有点大了,当一回标题党,之前在学JSP的时候提到了JSTL和EL表达式,由于一直钟情于Servlet,迟迟没有更新别的,这回算是跳出来了.这回放个大招 ...
- SetApartmentState(ApartmentState state).Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process
System.Threading.ThreadStateException: 'Current thread must be set to single thread apartment (STA) ...
- DevExpress的TreeList怎样设置数据源,从实例入手
场景 Winform控件-DevExpress18下载安装注册以及在VS中使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1 ...
- netcore sdk版本选择
NetCore sdk并不是每个版本都支持VS2017工具,也不是每个版本的sdk版本号和Runtime版本号都一样,这就需要我们在创建某个版本的net core应用时注意: 使用不同版本的vs时需要 ...
- JPA笔记1 ManyToOne
persistence.xml <?xml version="1.0" encoding="UTF-8"?> <persistence ver ...
- RV32I基础整数指令集
RV32I是32位基础整数指令集,它支持32位寻址空间,支持字节地址访问,仅支持小端格式(little-endian,高地址高位,低地址地位),寄存器也是32位整数寄存器.RV32I指令集的目的是尽量 ...