305:岛屿数量 II

This commit is contained in:
轩辕龙儿 2022-03-25 22:43:28 +08:00
parent 676d8c8075
commit e5d34bd3ea
4 changed files with 272 additions and 0 deletions

View File

@ -0,0 +1,43 @@
package com.code.leet.mode;
/**
* @description:
* @author: Administrator
* @date: 2022/3/25 22:27
*/
public class Union {// 并查集模板
int[] fa;
int[] sz;
public int Count;// 当前连通分量数目
public boolean united(int x, int y) {
x = find(x);
y = find(y);
return x == y;
}
public int find(int x) {
return fa[x] == x ? x : (fa[x] = find(fa[x]));
}
public Union(int n) {//构造函数+初始化
this.sz = new int[n];
for (int i = 0; i < n; i++) sz[i] = 1;
this.fa = new int[n];
for (int i = 0; i < n; i++) fa[i] = i;
this.Count = 0;
}
public void union(int x, int y) {
x = find(x);
y = find(y);
if (sz[x] < sz[y]) {
x ^= y;
y ^= x;
x ^= y;
}//按秩合并保证 sz[x]>=sz[y]
sz[x] += sz[y];
fa[y] = x;
--Count;//把秩小的unite到大的上
}
}

View File

@ -0,0 +1,135 @@
//给你一个大小为 m x n 的二进制网格 grid 网格表示一个地图其中0 表示水1 表示陆地最初grid 中的所有单元格都是水单元格所有
//单元格都是 0
//
// 可以通过执行 addLand 操作将某个位置的水转换成陆地给你一个数组 positions 其中 positions[i] = [ri, ci]
//要执行第 i 次操作的位置 (ri, ci)
//
// 返回一个整数数组 answer 其中 answer[i] 是将单元格 (ri, ci) 转换为陆地后地图中岛屿的数量
//
// 岛屿 的定义是被包围的陆地通过水平方向或者垂直方向上相邻的陆地连接而成你可以假设地图网格的四边均被无边无际的所包围
//
//
// 示例 1
//
//
//输入m = 3, n = 3, positions = [[0,0],[0,1],[1,2],[2,1]]
//输出[1,1,2,3]
//解释
//起初二维网格 grid 被全部注入0 代表1 代表陆地
//- 操作 #1addLand(0, 0)  grid[0][0] 的水变为陆地此时存在 1 个岛屿
//- 操作 #2addLand(0, 1)  grid[0][1] 的水变为陆地此时存在 1 个岛屿
//- 操作 #3addLand(1, 2)  grid[1][2] 的水变为陆地此时存在 2 个岛屿
//- 操作 #4addLand(2, 1)  grid[2][1] 的水变为陆地此时存在 3 个岛屿
//
//
// 示例 2
//
//
//输入m = 1, n = 1, positions = [[0,0]]
//输出[1]
//
//
//
//
// 提示
//
//
// 1 <= m, n, positions.length <= 10
// 1 <= m * n <= 10
// positions[i].length == 2
// 0 <= ri < m
// 0 <= ci < n
//
//
//
//
// 进阶你可以设计一个时间复杂度 O(k log(mn)) 的算法解决此问题吗其中 k == positions.length
// Related Topics 并查集 数组 👍 122 👎 0
package leetcode.editor.cn;
import java.util.ArrayList;
import java.util.List;
//305:岛屿数量 II
public class NumberOfIslandsIi {
public static void main(String[] args) {
Solution solution = new NumberOfIslandsIi().new Solution();
}
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public boolean G(int x, int m, int y, int n) {
return 0 <= x && x < m && 0 <= y && y < n;
}
public List<Integer> numIslands2(int m, int n, int[][] positions) {
Union set = new Union(m * n);
int[] vis = new int[m * n];
List<Integer> ans = new ArrayList<>();
for (int[] p : positions) {
int i = n * p[0] + p[1], nx = p[0], ny = p[1], x = 0, y = 0;
if (vis[i] == 1) {
ans.add(set.Count);
continue;
}
set.Count++;
vis[i] = 1;
x = nx;
y = ny + 1;
if (G(x, m, y, n) && vis[i + 1] == 1 && !set.united(i, i + 1)) set.union(i, i + 1);
x = nx;
y = ny - 1;
if (G(x, m, y, n) && vis[i - 1] == 1 && !set.united(i, i - 1)) set.union(i, i - 1);
x = nx + 1;
y = ny;
if (G(x, m, y, n) && vis[i + n] == 1 && !set.united(i, i + n)) set.union(i, i + n);
x = nx - 1;
y = ny;
if (G(x, m, y, n) && vis[i - n] == 1 && !set.united(i, i - n)) set.union(i, i - n);
ans.add(set.Count);
}
return ans;
}
}
class Union {// 并查集模板
int[] fa;
int[] sz;
public int Count;// 当前连通分量数目
public boolean united(int x, int y) {
x = find(x);
y = find(y);
return x == y;
}
public int find(int x) {
return fa[x] == x ? x : (fa[x] = find(fa[x]));
}
public Union(int n) {//构造函数+初始化
this.sz = new int[n];
for (int i = 0; i < n; i++) sz[i] = 1;
this.fa = new int[n];
for (int i = 0; i < n; i++) fa[i] = i;
this.Count = 0;
}
public void union(int x, int y) {
x = find(x);
y = find(y);
if (sz[x] < sz[y]) {
x ^= y;
y ^= x;
x ^= y;
}//按秩合并保证 sz[x]>=sz[y]
sz[x] += sz[y];
fa[y] = x;
--Count;//把秩小的unite到大的上
}
}
//leetcode submit region end(Prohibit modification and deletion)
}

View File

@ -0,0 +1,45 @@
<p>给你一个大小为 <code>m x n</code> 的二进制网格 <code>grid</code> 。网格表示一个地图,其中,<code>0</code> 表示水,<code>1</code> 表示陆地。最初,<code>grid</code> 中的所有单元格都是水单元格(即,所有单元格都是 <code>0</code>)。</p>
<p>可以通过执行 <code>addLand</code> 操作,将某个位置的水转换成陆地。给你一个数组 <code>positions</code> ,其中 <code>positions[i] = [r<sub>i</sub>, c<sub>i</sub>]</code> 是要执行第 <code>i</code> 次操作的位置 <code>(r<sub>i</sub>, c<sub>i</sub>)</code></p>
<p>返回一个整数数组 <code>answer</code> ,其中 <code>answer[i]</code> 是将单元格 <code>(r<sub>i</sub>, c<sub>i</sub>)</code> 转换为陆地后,地图中岛屿的数量。</p>
<p><strong>岛屿</strong> 的定义是被「水」包围的「陆地」,通过水平方向或者垂直方向上相邻的陆地连接而成。你可以假设地图网格的四边均被无边无际的「水」所包围。</p>
&nbsp;
<p><strong>示例 1</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/03/10/tmp-grid.jpg" style="width: 500px; height: 294px;" />
<pre>
<strong>输入:</strong>m = 3, n = 3, positions = [[0,0],[0,1],[1,2],[2,1]]
<strong>输出:</strong>[1,1,2,3]
<strong>解释:</strong>
起初,二维网格&nbsp;<code>grid</code>&nbsp;被全部注入「水」。0 代表「水」1 代表「陆地」)
- 操作&nbsp;#1<code>addLand(0, 0)</code>&nbsp;<code>grid[0][0]</code> 的水变为陆地。此时存在 1 个岛屿。
- 操作&nbsp;#2<code>addLand(0, 1)</code>&nbsp;<code>grid[0][1]</code> 的水变为陆地。此时存在 1 个岛屿。
- 操作&nbsp;#3<code>addLand(1, 2)</code>&nbsp;<code>grid[1][2]</code> 的水变为陆地。此时存在 2 个岛屿。
- 操作&nbsp;#4<code>addLand(2, 1)</code>&nbsp;<code>grid[2][1]</code> 的水变为陆地。此时存在 3 个岛屿。
</pre>
<p><strong>示例 2</strong></p>
<pre>
<strong>输入:</strong>m = 1, n = 1, positions = [[0,0]]
<strong>输出:</strong>[1]
</pre>
<p>&nbsp;</p>
<p><strong>提示:</strong></p>
<ul>
<li><code>1 &lt;= m, n, positions.length &lt;= 10<sup>4</sup></code></li>
<li><code>1 &lt;= m * n &lt;= 10<sup>4</sup></code></li>
<li><code>positions[i].length == 2</code></li>
<li><code>0 &lt;= r<sub>i</sub> &lt; m</code></li>
<li><code>0 &lt;= c<sub>i</sub> &lt; n</code></li>
</ul>
<p>&nbsp;</p>
<p><strong>进阶:</strong>你可以设计一个时间复杂度 <code>O(k log(mn))</code> 的算法解决此问题吗?(其中 <code>k == positions.length</code></p>
<div><div>Related Topics</div><div><li>并查集</li><li>数组</li></div></div><br><div><li>👍 122</li><li>👎 0</li></div>

View File

@ -0,0 +1,49 @@
### 模板
* java
```java
class Union {// 并查集模板
int[]fa;int[]sz;int Count;// 当前连通分量数目
public boolean united(int x,int y){x=find(x);y=find(y);return x==y;}
public int find(int x){return fa[x]==x?x:(fa[x]=find(fa[x]));}
public Union(int n) {//构造函数+初始化
this.sz=new int[n];for(int i=0;i<n;i++)sz[i]=1;
this.fa=new int[n];for(int i=0;i<n;i++)fa[i]=i;
this.Count=0;
}
public void union(int x,int y) {
x=find(x);y=find(y);
if(sz[x]<sz[y]){x^=y;y^=x;x^=y;}//按秩合并保证 sz[x]>=sz[y]
sz[x]+=sz[y];fa[y]=x;--Count;//把秩小的unite到大的上
}
}
```
### 求解
* java
```java
class Solution {
public boolean G(int x,int m,int y,int n){return 0<=x&&x<m&&0<=y&&y<n;}
public List<Integer> numIslands2(int m, int n, int[][] positions) {
Union set=new Union(m*n);
int[] vis=new int[m*n];
List<Integer>ans=new ArrayList<>();
for(int[] p:positions){
int i=n*p[0]+p[1],nx=p[0],ny=p[1],x=0,y=0;
if(vis[i]==1){ans.add(set.Count);continue;}
set.Count++;vis[i]=1;
x=nx;y=ny+1;if(G(x,m,y,n)&&vis[i+1]==1&&!set.united(i,i+1))set.union(i,i+1);
x=nx;y=ny-1;if(G(x,m,y,n)&&vis[i-1]==1&&!set.united(i,i-1))set.union(i,i-1);
x=nx+1;y=ny;if(G(x,m,y,n)&&vis[i+n]==1&&!set.united(i,i+n))set.union(i,i+n);
x=nx-1;y=ny;if(G(x,m,y,n)&&vis[i-n]==1&&!set.united(i,i-n))set.union(i,i-n);
ans.add(set.Count);
}
return ans;
}
}
```