岛屿数量(Number of Islands)
LeetCode传送门200. 岛屿数量
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
Given an m x n 2D binary grid grid which represents a map of '1's (land) and '0's (water), return the number of islands.
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: grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
Output: 1
Input: grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
Output: 3
Constraints:
- m == grid.length
- n == grid[i].length
- 1 <= m, n <= 300
grid[i][j] is '0' or '1'.
思考线
解题思路
方法一
遍历整个grid,如果当前数为1,则进入染色函数并将陆地的数值改为'2'.这样整个岛屿都会被染成2.直到遍历结束就得到了结果
function numIslands(grid: string[][]): number {
const m = grid.length;
const n = grid[0].length;
let res = 0;
for(let i = 0 ; i < m; i ++) {
for(let j = 0; j < n; j ++) {
if(grid[i][j] === '1') {
DFS(grid, i, j, m, n);
res ++;
}
}
}
return res;
};
function DFS(grid, i,j, m, n) {
if(grid[i][j] !== '1') return;
grid[i][j] = '2';
if(i-1 >=0) DFS(grid, i-1, j, m, n);
if(i+1 <m) DFS(grid, i+1, j, m, n);
if(j-1 >=0) DFS(grid, i, j -1, m, n);
if(j+1 <n) DFS(grid, i, j +1, m, n);
}
时间复杂度
时间复杂度:O(MN)O(M**N),其中 MM 和 NN 分别为行数和列数
方法二
同样的染色策略,这次我们使用BFS.
function numIslands(grid: string[][]): number {
const m = grid.length;
const n = grid[0].length;
let res = 0;
const queue = [];
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (grid[i][j] === '1') {
res++;
queue.push([i, j]);
grid[i][j] = '2';
while (queue.length) {
const [i, j] = queue.shift();
if (i - 1 >= 0 && grid[i - 1][j] === '1') {
queue.push([i - 1, j]);
grid[i - 1][j] = '2';
};
if (i + 1 < m && grid[i + 1][j] === '1') {
queue.push([i + 1, j]);
grid[i + 1][j] = '2'
};
if (j - 1 >= 0 && grid[i][j - 1] === '1') {
queue.push([i, j - 1]);
grid[i][j - 1] = '2'
}
if (j + 1 < n && grid[i][j + 1] === '1') {
queue.push([i, j + 1]);
grid[i][j+1] = '2'
}
}
}
}
}
return res;
};
方法三:并查集
使用并查集来解决本题:注意并查集初始化时让这个二维数组的数据和我们的集合实现一一对应,并保证其值的唯一性
function numIslands(grid: string[][]): number {
const set = new UnionSet(grid);
const m = grid.length;
const n = grid[0].length;
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (grid[i][j] === '1') {
grid[i][j] = '0';
if (i - 1 >= 0 && grid[i - 1][j] === '1') {
set.union(i * n + j, (i - 1) * n + j);
}
if (i + 1 < m && grid[i + 1][j] === '1') {
set.union(i * n + j, (i + 1) * n + j);
}
if (j - 1 >= 0 && grid[i][j - 1] === '1') {
set.union(i * n + j, i * n + (j - 1));
}
if (j + 1 < n && grid[i][j + 1] === '1') {
set.union(i * n + j, i * n + (j + 1));
}
}
}
}
return set.counts();
}
class UnionSet {
fa: number[] = [];
land = 0;
constructor(grid: string[][]) {
const m = grid.length;
const n = grid[0].length;
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
console.log('i * m + j', i * m +j * n)
if (grid[i][j] === '1') {
this.fa[i * n + j] = i * n + j; // 注意这个地方*n而不是m,只有*n才是一一对应关系
this.land++;
} else {
this.fa[i * n + j] = -1;
}
}
}
console.log(this.land);
}
union(ind1: number, ind2: number) {
console.log('this.land', this.land, ind1, ind2);
if (this.fa[this.find(ind1)] !== this.find(ind2)) {
this.fa[this.find(ind1)] = this.find(ind2);
this.land--;
}
}
find(ind: number) {
if (this.fa[ind] !== ind) {
this.fa[ind] = this.find(this.fa[ind]);
}
return this.fa[ind];
}
counts() {
return this.land;
}
}
时间复杂度
时间复杂度:O(MN * α(M**N))O(M**N),其中 MM 和 NN 分别为行数和列数。单次操作的时间复杂度为 α*(M**N)
这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。