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:

Given m = 3, n = 3, positions = [[0,0], [0,1], [1,2], [2,1]].
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
We return the result as an array: [1, 1, 2, 3] Challenge: Can you do it in time complexity O(k log mn), where k is the length of the positions?

Union Find

Princeton's lecture note on Union Find in Algorithms and Data Structures It is a well organized note with clear illustration describing from the naive QuickFind to the one with Weighting and Path compression. With Weighting and Path compression, The algorithm runs in

O((M+N) log* N) where M is the number of operations ( unite and find ), N is the number of objects, log* is iterated logarithm while the naive runs in O(MN).

方法一: Union Find based on Quick Find

我觉得:Union复杂度: O(M*N), where M is the number of calls of Union, and N is the size of id array, in our case N=m*n

Find复杂度: O(1)

实际运行时间199ms

 public class Solution {
public List<Integer> numIslands2(int m, int n, int[][] positions) {
int[][] dirs = new int[][]{{-1,0},{1,0},{0,1},{0,-1}};
unionFind uf = new unionFind(m*n);
List<Integer> res = new ArrayList<Integer>();
for (int[] pos : positions) {
int cur = pos[0]*n + pos[1];
uf.ids[cur] = cur;
uf.count++;
for (int[] dir : dirs) {
int x = dir[0] + pos[0];
int y = dir[1] + pos[1];
int nb = x*n+y;
if (x<0 || x>=m || y<0 || y>=n || uf.ids[nb]==-1) continue;
if (uf.find(nb) != uf.find(cur)) {
uf.union(nb, cur);
}
}
res.add(uf.count);
}
return res;
} public class unionFind {
int[] ids;
int count;
public unionFind(int num) {
this.ids = new int[num];
Arrays.fill(ids, -1);
this.count = 0;
}
public int find(int num) {
return ids[num];
}
public boolean union(int n1, int n2) {
int id1=ids[n1], id2=ids[n2];
if (id1 != id2) {
for (int i=0; i<ids.length; i++) {
if (ids[i] == id2) {
ids[i] = id1;
}
}
count--;
return true;
}
return false;
}
}
}

Faster Union Find方法2:Union Find Based on Quick Union 参考:https://leetcode.com/discuss/69572/easiest-java-solution-with-explanations

Quick Union is Faster than Quick Find

The idea is simple. To represent a list of islands, we use trees. i.e., a list of roots. This helps us find the identifier of an island faster. If roots[c] = p means the parent of node c is p, we can climb up the parent chain to find out the identifier of an island, i.e., which island this point belongs to:

Do root[root[roots[c]]]... until root[c] == c;

To transform the two dimension problem into the classic UF, perform a linear mapping:

int id = n * x + y;

Initially assume every cell are in non-island set {-1}. When point A is added, we create a new root, i.e., a new island. Then, check if any of its 4 neighbors belong to the same island. If not,union the neighbor by setting the root to be the same. Remember to skip non-island cells.

我觉得:Union复杂度: O(M*logN), where M is the number of calls of Union, and N is the size of id array, in our case N=m*n

Find复杂度: O(logN)

实际运行28ms

 public class Solution {
public List<Integer> numIslands2(int m, int n, int[][] positions) {
int[][] dirs = new int[][]{{-1,0},{1,0},{0,1},{0,-1}};
unionFind uf = new unionFind(m*n);
List<Integer> res = new ArrayList<Integer>();
for (int[] pos : positions) {
int cur = pos[0]*n + pos[1];
uf.ids[cur] = cur;
uf.count++;
for (int[] dir : dirs) {
int x = dir[0] + pos[0];
int y = dir[1] + pos[1];
int nb = x*n+y;
if (x<0 || x>=m || y<0 || y>=n || uf.ids[nb]==-1) continue;
int rootNb = uf.root(nb);
int rootCur = uf.root(cur);
if (rootCur != rootNb) { //not connect
uf.union(rootCur, rootNb);
uf.count--;
}
}
res.add(uf.count);
}
return res;
} public class unionFind { //ids[]记录上一跳pos,root记录最上面的pos,union(i, j)修改i的root的上一跳为j的root
int[] ids;
int count;
public unionFind(int num) {
this.ids = new int[num];
Arrays.fill(ids, -1);
this.count = 0;
} public int root(int i) { //FIND operation is proportional to the depth of the tree.the average running time is O(logN)
while (ids[i] != i) i = ids[i];
return i;
} public boolean isConnected(int i, int j) {
return root(i) == root(j);
} public void union(int i, int j) {
int iRoot = root(i);
int jRoot = root(j);
ids[iRoot] = jRoot;
}
}
}

Summary of Union Find:

Princeton's lecture note on Union Find

Quick Find

Quick Union

Here is a very easy understanding video by Stanford(看3:00开始的例子,非常简单, 一看就懂)

Compare of Fast Find & Fast Union, though worst case time complexity is almost the same, fast union is faster than fast find

Leetcode: Number of Islands II && Summary of Union Find的更多相关文章

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

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

  3. [LeetCode] Number of Islands II

    Problem Description: A 2d grid map of m rows and n columns is initially filled with water. We may pe ...

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

  5. [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 oper ...

  6. LeetCode 305. Number of Islands II

    原题链接在这里:https://leetcode.com/problems/number-of-islands-ii/ 题目: A 2d grid map of m rows and n column ...

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

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

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

随机推荐

  1. Introducing the Accelerated Mobile Pages Project, for a faster, open mobile web

    https://googleblog.blogspot.com/2015/10/introducing-accelerated-mobile-pages.html October 7, 2015 Sm ...

  2. Apache Kafka源码分析 - ReplicaStateMachine

    startup 在onControllerFailover中被调用, /** * Invoked on successful controller election. First registers ...

  3. Vaadin

    Vaadin 这个是用Java 做的  一个人就可以完成 你去网上搜一下  教程 https://vaadin.com/home  官网 http://baike.baidu.com/link?url ...

  4. zepto源码--isEmptyObject,isNumeric,inArray,trim--学习笔记

    1.isEmptyObject,判断对象是否为空对象的函数 定义变量name,遍历传入对象的属性name,如果存在任何属性,则返回false,判定传入的参数为非空对象,否则即为空对象. 2.isNum ...

  5. RTSP交互命令简介及过程参数描述

    目录 [hide] 1 RTSP消息格式 2 简单的rtsp交互过程 3 rtsp中常用方法 3.1 OPTION 3.2 DESCRIBE 3.3 SETUP 3.4 PLAY 3.5 PAUSE ...

  6. mongo安装、备份与常见命令整理

    http://zlboy888.blog.163.com/blog/static/315357072012919241104/ 1 下载安装包  官方下载地址:http://www.mongodb.o ...

  7. OO之美4(好代码与坏代码)

    前言:写代码不仅仅要做到能与机器交流,更要做到能和人交流 编码规范:编码规范就是最佳实践,是前辈在编码这件事上的积累和总结,是智慧的延续和工业的实践,如下: ⑴命名规范 ⑵避免行数过多的方法 ⑶代码缩 ...

  8. Asp.net MVC 批量删除数据

    ProductList视图 <div class="mid"> <div id="editInfo"> @using (Html.Beg ...

  9. 用Dictionary代替if

    public Dictionary<string, System.Drawing.RotateFlipType> dicRFT = new Dictionary<string, Sy ...

  10. 对memcpy函数的改进

    void *mymemcpy(void *dst,const void *src,size_t num) { assert((dst!=NULL)&&(src!=NULL)); int ...