--- comments: true difficulty: 中等 edit_url: https://github.com/doocs/leetcode/edit/main/solution/0200-0299/0200.Number%20of%20Islands/README.md tags: - 深度优先搜索 - 广度优先搜索 - 并查集 - 数组 - 矩阵 --- # [200. 岛屿数量](https://leetcode.cn/problems/number-of-islands) [English Version](/solution/0200-0299/0200.Number%20of%20Islands/README_EN.md) ## 题目描述

给你一个由 '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

 

提示:

## 解法 ### 方法一:DFS 我们可以使用深度优先搜索(DFS)来遍历每个岛屿。遍历网格中的每个单元格 $(i, j)$,如果该单元格的值为 '1',则说明我们找到了一个新的岛屿。我们可以从该单元格开始进行 DFS,将与之相连的所有陆地单元格的值都标记为 '0',以避免重复计数。每次找到一个新的岛屿时,我们将岛屿数量加 1。 时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别为网格的行数和列数。 #### Python3 ```python class Solution: def numIslands(self, grid: List[List[str]]) -> int: def dfs(i, j): grid[i][j] = '0' for a, b in pairwise(dirs): x, y = i + a, j + b if 0 <= x < m and 0 <= y < n and grid[x][y] == '1': dfs(x, y) ans = 0 dirs = (-1, 0, 1, 0, -1) m, n = len(grid), len(grid[0]) for i in range(m): for j in range(n): if grid[i][j] == '1': dfs(i, j) ans += 1 return ans ``` #### Java ```java class Solution { private char[][] grid; private int m; private int n; public int numIslands(char[][] grid) { m = grid.length; n = grid[0].length; this.grid = grid; int ans = 0; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == '1') { dfs(i, j); ++ans; } } } return ans; } private void dfs(int i, int j) { grid[i][j] = '0'; int[] dirs = {-1, 0, 1, 0, -1}; for (int k = 0; k < 4; ++k) { int x = i + dirs[k]; int y = j + dirs[k + 1]; if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1') { dfs(x, y); } } } } ``` #### C++ ```cpp class Solution { public: int numIslands(vector>& grid) { int m = grid.size(); int n = grid[0].size(); int ans = 0; int dirs[5] = {-1, 0, 1, 0, -1}; auto dfs = [&](this auto&& dfs, int i, int j) -> void { grid[i][j] = '0'; for (int k = 0; k < 4; ++k) { int x = i + dirs[k], y = j + dirs[k + 1]; if (x >= 0 && x < grid.size() && y >= 0 && y < grid[0].size() && grid[x][y] == '1') { dfs(x, y); } } }; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == '1') { dfs(i, j); ++ans; } } } return ans; } }; ``` #### Go ```go func numIslands(grid [][]byte) int { m, n := len(grid), len(grid[0]) var dfs func(i, j int) dfs = func(i, j int) { grid[i][j] = '0' dirs := []int{-1, 0, 1, 0, -1} for k := 0; k < 4; k++ { x, y := i+dirs[k], j+dirs[k+1] if x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1' { dfs(x, y) } } } ans := 0 for i := 0; i < m; i++ { for j := 0; j < n; j++ { if grid[i][j] == '1' { dfs(i, j) ans++ } } } return ans } ``` #### TypeScript ```ts function numIslands(grid: string[][]): number { const m = grid.length; const n = grid[0].length; let ans = 0; const dirs = [-1, 0, 1, 0, -1]; const dfs = (i: number, j: number) => { grid[i][j] = '0'; for (let k = 0; k < 4; ++k) { const x = i + dirs[k]; const y = j + dirs[k + 1]; if (grid[x]?.[y] === '1') { dfs(x, y); } } }; for (let i = 0; i < m; ++i) { for (let j = 0; j < n; ++j) { if (grid[i][j] === '1') { dfs(i, j); ans++; } } } return ans; } ``` #### Rust ```rust const DIRS: [i32; 5] = [-1, 0, 1, 0, -1]; impl Solution { pub fn num_islands(grid: Vec>) -> i32 { fn dfs(grid: &mut Vec>, i: usize, j: usize) { grid[i][j] = '0'; for k in 0..4 { let x = (i as i32) + DIRS[k]; let y = (j as i32) + DIRS[k + 1]; if x >= 0 && (x as usize) < grid.len() && y >= 0 && (y as usize) < grid[0].len() && grid[x as usize][y as usize] == '1' { dfs(grid, x as usize, y as usize); } } } let mut grid = grid; let mut ans = 0; for i in 0..grid.len() { for j in 0..grid[0].len() { if grid[i][j] == '1' { dfs(&mut grid, i, j); ans += 1; } } } ans } } ``` #### C# ```cs public class Solution { public int NumIslands(char[][] grid) { int m = grid.Length; int n = grid[0].Length; int ans = 0; int[] dirs = { -1, 0, 1, 0, -1 }; void Dfs(int i, int j) { grid[i][j] = '0'; for (int k = 0; k < 4; ++k) { int x = i + dirs[k]; int y = j + dirs[k + 1]; if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1') { Dfs(x, y); } } } for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == '1') { Dfs(i, j); ans++; } } } return ans; } } ``` ### 方法二:BFS 我们也可以使用广度优先搜索(BFS)来遍历每个岛屿。遍历网格中的每个单元格 $(i, j)$,如果该单元格的值为 '1',则说明我们找到了一个新的岛屿。我们可以从该单元格开始进行 BFS,将与之相连的所有陆地单元格的值都标记为 '0',以避免重复计数。每次找到一个新的岛屿时,我们将岛屿数量加 1。 BFS 的具体过程如下: 1. 将起始单元格 $(i, j)$ 入队,并将其值标记为 '0'。 2. 当队列不为空时,执行以下操作: - 出队一个单元格 $p$。 - 遍历 $p$ 的四个相邻单元格 $(x, y)$,如果 $(x, y)$ 在网格范围内且值为 '1',则将其入队并将其值标记为 '0'。 时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别为网格的行数和列数。 #### Python3 ```python class Solution: def numIslands(self, grid: List[List[str]]) -> int: def bfs(i, j): grid[i][j] = '0' q = deque([(i, j)]) while q: i, j = q.popleft() for a, b in pairwise(dirs): x, y = i + a, j + b if 0 <= x < m and 0 <= y < n and grid[x][y] == '1': q.append((x, y)) grid[x][y] = 0 ans = 0 dirs = (-1, 0, 1, 0, -1) m, n = len(grid), len(grid[0]) for i in range(m): for j in range(n): if grid[i][j] == '1': bfs(i, j) ans += 1 return ans ``` #### Java ```java class Solution { private char[][] grid; private int m; private int n; public int numIslands(char[][] grid) { m = grid.length; n = grid[0].length; this.grid = grid; int ans = 0; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == '1') { bfs(i, j); ++ans; } } } return ans; } private void bfs(int i, int j) { grid[i][j] = '0'; Deque q = new ArrayDeque<>(); q.offer(new int[] {i, j}); int[] dirs = {-1, 0, 1, 0, -1}; while (!q.isEmpty()) { int[] p = q.poll(); for (int k = 0; k < 4; ++k) { int x = p[0] + dirs[k]; int y = p[1] + dirs[k + 1]; if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1') { q.offer(new int[] {x, y}); grid[x][y] = '0'; } } } } } ``` #### C++ ```cpp class Solution { public: int numIslands(vector>& grid) { int m = grid.size(); int n = grid[0].size(); int ans = 0; int dirs[5] = {-1, 0, 1, 0, -1}; auto bfs = [&](int i, int j) -> void { grid[i][j] = '0'; queue> q; q.push({i, j}); while (!q.empty()) { auto [a, b] = q.front(); q.pop(); for (int k = 0; k < 4; ++k) { int x = a + dirs[k]; int y = b + dirs[k + 1]; if (x >= 0 && x < grid.size() && y >= 0 && y < grid[0].size() && grid[x][y] == '1') { q.push({x, y}); grid[x][y] = '0'; } } } }; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == '1') { bfs(i, j); ++ans; } } } return ans; } }; ``` #### Go ```go func numIslands(grid [][]byte) int { m, n := len(grid), len(grid[0]) bfs := func(i, j int) { grid[i][j] = '0' q := [][]int{[]int{i, j}} dirs := []int{-1, 0, 1, 0, -1} for len(q) > 0 { p := q[0] q = q[1:] for k := 0; k < 4; k++ { x, y := p[0]+dirs[k], p[1]+dirs[k+1] if x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1' { q = append(q, []int{x, y}) grid[x][y] = '0' } } } } ans := 0 for i := 0; i < m; i++ { for j := 0; j < n; j++ { if grid[i][j] == '1' { bfs(i, j) ans++ } } } return ans } ``` #### TypeScript ```ts function numIslands(grid: string[][]): number { const m = grid.length; const n = grid[0].length; let ans = 0; const bfs = (i: number, j: number) => { grid[i][j] = '0'; const q = [[i, j]]; const dirs = [-1, 0, 1, 0, -1]; for (const [i, j] of q) { for (let k = 0; k < 4; ++k) { const x = i + dirs[k]; const y = j + dirs[k + 1]; if (grid[x]?.[y] == '1') { q.push([x, y]); grid[x][y] = '0'; } } } }; for (let i = 0; i < m; ++i) { for (let j = 0; j < n; ++j) { if (grid[i][j] == '1') { bfs(i, j); ++ans; } } } return ans; } ``` #### Rust ```rust use std::collections::VecDeque; const DIRS: [i32; 5] = [-1, 0, 1, 0, -1]; impl Solution { pub fn num_islands(grid: Vec>) -> i32 { fn bfs(grid: &mut Vec>, i: usize, j: usize) { grid[i][j] = '0'; let mut queue = VecDeque::from([(i, j)]); while !queue.is_empty() { let (i, j) = queue.pop_front().unwrap(); for k in 0..4 { let x = (i as i32) + DIRS[k]; let y = (j as i32) + DIRS[k + 1]; if x >= 0 && (x as usize) < grid.len() && y >= 0 && (y as usize) < grid[0].len() && grid[x as usize][y as usize] == '1' { grid[x as usize][y as usize] = '0'; queue.push_back((x as usize, y as usize)); } } } } let mut grid = grid; let mut ans = 0; for i in 0..grid.len() { for j in 0..grid[0].len() { if grid[i][j] == '1' { bfs(&mut grid, i, j); ans += 1; } } } ans } } ``` ### 方法三: 并查集 我们可以使用并查集(Union-Find)来解决这个问题。遍历网格中的每个单元格 $(i, j)$,如果该单元格的值为 '1',则将其与相邻的陆地单元格进行合并。最后,我们统计并查集中不同根节点的数量,即为岛屿的数量。 时间复杂度 $O(m \times n \times \log (m \times n))$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别为网格的行数和列数。 #### Python3 ```python class Solution: def numIslands(self, grid: List[List[str]]) -> int: def find(x): if p[x] != x: p[x] = find(p[x]) return p[x] dirs = (0, 1, 0) m, n = len(grid), len(grid[0]) p = list(range(m * n)) for i in range(m): for j in range(n): if grid[i][j] == '1': for a, b in pairwise(dirs): x, y = i + a, j + b if x < m and y < n and grid[x][y] == '1': p[find(i * n + j)] = find(x * n + y) return sum( grid[i][j] == '1' and i * n + j == find(i * n + j) for i in range(m) for j in range(n) ) ``` #### Java ```java class Solution { private int[] p; public int numIslands(char[][] grid) { int m = grid.length; int n = grid[0].length; p = new int[m * n]; for (int i = 0; i < p.length; ++i) { p[i] = i; } int[] dirs = {1, 0, 1}; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == '1') { for (int k = 0; k < 2; ++k) { int x = i + dirs[k]; int y = j + dirs[k + 1]; if (x < m && y < n && grid[x][y] == '1') { p[find(x * n + y)] = find(i * n + j); } } } } } int ans = 0; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == '1' && i * n + j == find(i * n + j)) { ++ans; } } } return ans; } private int find(int x) { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; } } ``` #### C++ ```cpp class Solution { public: int numIslands(vector>& grid) { int m = grid.size(); int n = grid[0].size(); vector p(m * n); iota(p.begin(), p.end(), 0); function find = [&](int x) -> int { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; }; int dirs[3] = {1, 0, 1}; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == '1') { for (int k = 0; k < 2; ++k) { int x = i + dirs[k]; int y = j + dirs[k + 1]; if (x < m && y < n && grid[x][y] == '1') { p[find(x * n + y)] = find(i * n + j); } } } } } int ans = 0; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { ans += grid[i][j] == '1' && i * n + j == find(i * n + j); } } return ans; } }; ``` #### Go ```go func numIslands(grid [][]byte) int { m, n := len(grid), len(grid[0]) p := make([]int, m*n) for i := range p { p[i] = i } var find func(x int) int find = func(x int) int { if p[x] != x { p[x] = find(p[x]) } return p[x] } dirs := []int{1, 0, 1} for i := 0; i < m; i++ { for j := 0; j < n; j++ { if grid[i][j] == '1' { for k := 0; k < 2; k++ { x, y := i+dirs[k], j+dirs[k+1] if x < m && y < n && grid[x][y] == '1' { p[find(x*n+y)] = find(i*n + j) } } } } } ans := 0 for i := 0; i < m; i++ { for j := 0; j < n; j++ { if grid[i][j] == '1' && i*n+j == find(i*n+j) { ans++ } } } return ans } ``` #### TypeScript ```ts function numIslands(grid: string[][]): number { const m = grid.length; const n = grid[0].length; const p: number[] = Array.from({ length: m * n }, (_, i) => i); function find(x: number): number { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; } const dirs = [1, 0, 1]; for (let i = 0; i < m; ++i) { for (let j = 0; j < n; ++j) { if (grid[i][j] == '1') { for (let k = 0; k < 2; ++k) { const x = i + dirs[k]; const y = j + dirs[k + 1]; if (grid[x]?.[y] == '1') { p[find(i * n + j)] = find(x * n + y); } } } } } let ans = 0; for (let i = 0; i < m; ++i) { for (let j = 0; j < n; ++j) { if (grid[i][j] == '1' && i * n + j == find(i * n + j)) { ++ans; } } } return ans; } ``` #### Rust ```rust const DIRS: [usize; 3] = [1, 0, 1]; impl Solution { pub fn num_islands(grid: Vec>) -> i32 { let m = grid.len(); let n = grid[0].len(); let mut p: Vec = (0..(m * n) as i32).collect(); fn find(p: &mut Vec, x: usize) -> i32 { if p[x] != (x as i32) { p[x] = find(p, p[x] as usize); } p[x] } for i in 0..m { for j in 0..n { if grid[i][j] == '1' { for k in 0..2 { let x = i + DIRS[k]; let y = j + DIRS[k + 1]; if x < m && y < n && grid[x][y] == '1' { let f1 = find(&mut p, x * n + y); let f2 = find(&mut p, i * n + j); p[f1 as usize] = f2; } } } } } let mut ans = 0; for i in 0..m { for j in 0..n { if grid[i][j] == '1' && p[i * n + j] == ((i * n + j) as i32) { ans += 1; } } } ans } } ```