Google 2016 面试题5 | 岛屿计数2
来源:互联网 发布:windows系统启动 efi 编辑:程序博客网 时间:2024/05/17 08:24
题目描述
给出一个m行n列的网格地图,每个位置为0或1,0表示海水1表示陆地。一开始地图全为0(没有陆地)。每次在一个位置加入一块陆地,返回此时地图中陆地的总块数(相邻陆地统计时为同一块陆地)。
Example:
操作#1: addLand(0, 0) turns the water at grid[0][0] into a land.
操作#2: addLand(0, 1) turns the water at grid[0][1] into a land.
操作#3: addLand(1, 2) turns the water at grid[1][2] into a land.
操作#4: addLand(2, 1) turns the water at grid[2][1] into a land.
返回答案数组: [1, 1, 2, 3]
你可以做到复杂度O(k log mn)吗?其中k为操作次数。
分析解答
对于一个静态的地图,统计岛屿个数可以使用dfs(类似于寻找一个图中的连通块个数),算法复杂度是O(m*n)。但是对于一个不断更新的地图,如果我们每次重新统计连通块个数,复杂度为O(m*n*k),其中k为总操作个数。考虑到每次只有一个位置发生变化(从0变为1),完全不必重新统一,该陆地的产生职能影响周围四个位置。假设该陆地周围有t(p至多为4)个不连通的岛屿,那么该陆地为把这四个不同点岛屿合并为一个岛屿,使得总岛屿数下降t-1个。因此我们需要维护岛屿之间的连通性,自然的我们想到了并查集。并查集是一种解决此类问题的强力数据结构,以此题为例,初始时每个位置都是独立的、互不连通的,每个位置都有一个标签来identify自己,记录在fa数组中,fa[i]为i。当两个位置p、q相邻且都为1时,这两个位置需要统一它们的标签(表示这两个岛屿合并),即fa[p] = q。但是p、q的标签可能已经被修改,因此我们需要通过getfather函数递归找到它们的真实标签(getfather(i)的返回值也称为i的祖先),合并操作变为fa[getfather(p)] = getfather(q)。为了防止最坏情况下每次调用getfather函数都要经过m*n次递归,我们可以采用路径压缩的方法(详见代码中getfather函数),使得每个位置到其祖先的距离始终为一个很小的常数(与m、n无关)。本题中总体时间复杂度为O(m*n+k),其中每次并查集的查询复杂度为一个常数(不超过4)。
参考代码
class Solution {public: vector<int> numIslands2(int m, int n, vector<vector<int> >& positions) { bool land[m][n]; int dr[4] = {1, 0, -1, 0}; int dc[4] = {0, -1, 0, 1}; int fa[m * n]; int island = 0; vector<int> ret; // initialization memset(land, 0, sizeof(land)); for (int i=0; i<m*n; i++) fa[i] = i; for (int i=0; i<positions.size(); i++) { island++; int x = positions[i][0], y = positions[i][1]; int f = x * n + y; land[x][y] = true; for (int j=0; j<4; j++) { // 4 direction check int tx = x + dr[j]; int ty = y + dc[j]; if (tx >=0 && tx < m && ty >= 0 && ty < n && land[tx][ty] && getfather(fa, tx*n+ty) != f) { fa[getfather(fa, tx*n+ty)] = f; island--; } } ret.push_back(island); } return ret; } // disjoint-set and path compression int getfather(int fa[], int i) { if (fa[i] == i) return i; return fa[i] = getfather(fa, fa[i]); }};
- Google 2016 面试题5 | 岛屿计数2
- Google 2016 面试题5 | 岛屿计数2
- Google面试题 | 数字计数
- Google面试题:数字计数
- Google算法题:岛屿计数II
- Google 2016面试题
- 面试题2-- Google
- Google 2016 面试题6 | Count of Smaller Numbers After Self(数组计数)
- Google 2016 面试题6 | Count of Smaller Numbers After Self(数组计数)
- 九章算法面试题81 岛屿的个数
- Google 2016 面试题 2 | 摆动排序 II
- 面试题:应用计数原理
- Google 2016 面试题 | 数组补丁
- Google 2016 面试题1 | 数组补丁
- google面试题5-Balanced Partition
- Google 面试题讨论
- 小小Google面试题
- google面试题
- BOM getElement
- linux下devicetree中惯用的of函数
- Latex字体未嵌入解决方案
- 快速掌握一个语言最常用的50%
- 自学安卓开发基础总结2_四大组件_Activty
- Google 2016 面试题5 | 岛屿计数2
- Hibernate 多对一查询,以及一对多关联删除
- IE8 OCX 无法进入DEBUG
- 打印功能
- POJ 3261 Milk Patterns
- 建立自增序列
- fresco 显示缩略图,不直接使用setImageURI,防止卡顿和显示不全:纯黑色或纯白色
- WaitUntil和WaitWhile
- 解决UITableViewCell 上放置 UIScrollView 两者手势冲突