「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战」
题目描述
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [ ["1","1","1","1","0"], ["1","1","0","1","0"], ["1","1","0","0","0"], ["0","0","0","0","0"] ] 输出:1
示例 2:
输入:grid = [ ["1","1","0","0","0"], ["1","1","0","0","0"], ["0","0","1","0","0"], ["0","0","0","1","1"] ] 输出:3
提示:
- m == grid.length
- n == grid[i].length
- 1 <= m, n <= 300
- grid[i][j] 的值为 '0' 或 '1'
解法1:并查集
思路:
- 1不代表岛屿,岛屿可以由1个或者很多个1组成
- 水平方向和/或竖直方向上相邻的陆地链接: 意思是如果某个'1'和 水平和/或竖竖直方向 的其他1邻接,说明这个1不是独立的,属于某一片岛屿
- 只有完全没有邻接1的"一片1"才属于另一个独立岛屿,也就是岛屿数+1
class Solution {
public int numIslands(char[][] grid) {
DisjointSet djs = new DisjointSet(grid.length * grid[0].length);
Set<Integer> island = new HashSet<>();
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == '1') {
int djsIndex = calIndex(grid, i, j);
union(grid, djsIndex, i - 1, j, djs);
union(grid, djsIndex, i, j - 1, djs);
union(grid, djsIndex, i + 1, j, djs);
union(grid, djsIndex, i, j + 1, djs);
island.add(djsIndex);
}
}
}
Set<Integer> res = new HashSet<>();
for (Integer integer : island) {
res.add(djs.find(integer));
}
return res.size();
}
private void union(char[][] grid, int index, int i, int j, DisjointSet djs) {
if (canVisited(grid, i, j) && grid[i][j] == '1') {
djs.union(index, calIndex(grid, i, j));
}
}
private boolean canVisited(char[][] grid, int i, int j) {
return i >= 0 && i < grid.length && j >= 0 && j < grid[i].length;
}
public int calIndex(char[][] grid, int i, int j) {
return i * grid[i].length + j;
}
class DisjointSet {
public DisjointSet(int count) {
this.count = count;
this.parent = new int[count];
for (int i = 0; i < parent.length; i++) {
parent[i] = i;
}
}
final int[] parent;
int count = 0;
public int find(int i) {
while (parent[i] != i) {
parent[i] = parent[parent[i]];
i = parent[i];
}
return parent[i];
}
public void compress() {
for (int i = 0; i < parent.length; i++) {
find(i);
}
}
public int union(int i, int j) {
int pi = find(i);
int pj = find(j);
if (pi != pj) {
parent[pj] = pi;
count--;
}
return pi;
}
}
解法二:DFS
思路:就是通过遍历每一个格子,然后深度递归所有的周围点,遍历之后置2,然后继续遍历周围的格子,如果遇到2或0就结束(即return),知道没有了,就返回主函数,相当于遍历了一遍这个陆地,res++。然后再继续找下一个格子进行遍历,直遍历完毕。
class Solution {
public int numIslands(char[][] grid) {
if(grid == null) return 0;
int n = grid.length;
int m = grid[0].length;
int res = 0;
boolean[][] marked = new boolean[n][m];
if(n == 0 || m==0) return 0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(grid[i][j] == '1' && !marked[i][j]){
dfs(grid,marked,i,j);
res++;
}
}
}
return res;
}
public void dfs(char[][] arr,boolean[][] marked,int x,int y){
marked[x][y] = true;
int n = arr.length;
int m = arr[0].length;
//上
if(x>0 && !marked[x-1][y] && arr[x-1][y] == '1'){
dfs(arr,marked,x-1,y);
}
//下
if(x<n-1 && !marked[x+1][y] && arr[x+1][y] == '1'){
dfs(arr,marked,x+1,y);
}
//左
if(y>0 && !marked[x][y-1] && arr[x][y-1] == '1'){
dfs(arr,marked,x,y-1);
}
//右
if(y<m-1 && !marked[x][y+1] && arr[x][y+1] == '1'){
dfs(arr,marked,x,y+1);
}
return;
}
}