99. 岛屿数量
题目描述:
给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。
输入描述:
第一行包含两个整数 N, M,表示矩阵的行数和列数。
后续 N 行,每行包含 M 个数字,数字为 1 或者 0。
输出描述:
输出一个整数,表示岛屿的数量。如果不存在岛屿,则输出 0。
输入示例:
根据测试案例中所展示,岛屿数量共有 3 个,所以输出 3。
思路
深度优先搜索
注意题目中每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
也就是说斜角度链接是不算了, 例如示例二,是三个岛屿,如图:
考虑遇到一个没有访问过的节点陆地,计数器就加1,然后把该节点陆地所能遍历到的陆地都标记上。
再遇到标记过的陆地节点和海洋节点的时候直接跳过。这样就得到了岛屿的最终数量。
广度优先搜索
这里有一个广搜中很重要的细节:
根本原因是只要 加入队列就代表 走过,就需要标记,而不是从队列拿出来的时候再去标记走过。
如果从队列拿出节点,再去标记这个节点走过,就会发生下图所示的结果,会导致很多节点重复加入队列。
代码
C++深度优先搜索(DFS这里只起到标记位置的作用,一次找出整个岛)
#include <iostream>
#include <vector>
using namespace std;int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
void dfs(const vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) {for (int i = 0; i < 4; ++i) {int nextx = x + dir[i][0];int nexty = y + dir[i][1];if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) {continue; // 越界了,直接跳过}if (!visited[nextx][nexty] && grid[nextx][nexty] == 1) {// 没有访问过,同时是陆地visited[nextx][nexty] = true;dfs(grid, visited, nextx, nexty);}}
}int main() {int n, m;cin >> n >> m;vector<vector<int>> grid(n, vector<int>(m, 0));for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {cin >> grid[i][j];}}vector<vector<bool>> visited(n, vector<bool>(m, false));int result = 0;for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (!visited[i][j] && grid[i][j] == 1) {visited[i][j] = true;result++;dfs(grid, visited, i, j); // 将与其链接的岛屿都标记上true}}}cout << result << endl;
}
C++广度优先搜索(把同一个岛屿的遍历在一个BFS内完成)
#include <iostream>
#include <vector>
#include <queue>
using namespace std;int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
void bfs(const vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) {queue<pair<int, int>> que;que.push({x, y});visited[x][y] = true;while (!que.empty()) {pair<int, int> cur = que.front(); que.pop();int curx = cur.first;int cury = cur.second;for (int i = 0; i < 4; ++i) {int nextx = curx + dir[i][0];int nexty = cury + dir[i][1];if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;if (!visited[nextx][nexty] && grid[nextx][nexty] == 1) {que.push({nextx, nexty}); // 压进队列,之后再检查。而不是像DFS一样,一路走到底。(没有BFS的套用)visited[nextx][nexty] = true; // 只要压进队列立刻标记}}}
}int main() {int n, m;cin >> n >> m;vector<vector<int>> grid(n, vector<int>(m, 0));for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {cin >> grid[i][j];}}vector<vector<bool>> visited(n, vector<bool>(m, false));int result = 0;for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (!visited[i][j] && grid[i][j] == 1) {visited[i][j] = true;result++; // 结果再进入BFS之前累加,因为找到了新岛屿bfs(grid, visited, i, j); // 将与其链接的岛屿都标记上true}}}cout << result << endl;
}
Python深度优先搜索
from collections import dequedir = [(0, 1), (1, 0), (0, -1), (-1, 0)]def dfs(grid, visited, x, y):for dx, dy in dir:nextx, nexty = x + dx, y + dyif nextx < 0 or nextx >= len(grid) or nexty < 0 or nexty >= len(grid[0]):continueif grid[nextx][nexty] == 1 and not visited[nextx][nexty]:visited[nextx][nexty] = Truedfs(grid, visited, nextx, nexty)def main():n, m = map(int, input().split())grid = [list(map(int, input().split())) for _ in range(n)] # 'map'函数返回的是一个迭代器,而不是一个列表。为了将其转换为列表,我们使用 list() 函数将迭代器转化为一个具体的列表。visited = [[False] * (m) for _ in range(n)]result = 0for i in range(n):for j in range(m):if (grid[i][j] == 1 and not visited[i][j]):result += 1visited[i][j] = Truedfs(grid, visited, i, j)print(result)if __name__ == "__main__":main()
Python广度优先搜索
from collections import dequedir = [(0, 1), (1, 0), (0, -1), (-1, 0)]def bfs(grid, visited, x, y):queue = deque([(x, y)])visited[x][y] = Truewhile (queue):curx, cury = queue.popleft()for dx, dy in dir:nextx, nexty = curx + dx, cury + dyif nextx < 0 or nextx >= len(grid) or nexty < 0 or nexty >= len(grid[0]): # 注意这里从0开始所以比n,m小1,如果等于的时候实际上已经越界continueif not visited[nextx][nexty] and grid[nextx][nexty] == 1:queue.append((nextx, nexty))visited[nextx][nexty] = Truedef main():n, m = map(int, input().split())grid = [list(map(int, input().split())) for _ in range(n)] # 'map'函数返回的是一个迭代器,而不是一个列表。为了将其转换为列表,我们使用 list() 函数将迭代器转化为一个具体的列表。visited = [[False] * (m) for _ in range(n)]result = 0for i in range(n):for j in range(m):if (grid[i][j] == 1 and not visited[i][j]):result += 1visited[i][j] = Truebfs(grid, visited, i, j)print(result)if __name__ == "__main__":main()
Leetcode 200. Number of Islands
C++广度优先搜索 (字符用单引号,字符串用双引号)
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
class Solution {
public:int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};void bfs(const vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {queue<pair<int, int>> que;que.push({x, y});visited[x][y] = true;while (!que.empty()) {pair<int, int> cur = que.front(); que.pop();int curx = cur.first;int cury = cur.second;for (int i = 0; i < 4; ++i) {int nextx = curx + dir[i][0];int nexty = cury + dir[i][1];if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;if (!visited[nextx][nexty] && grid[nextx][nexty] == '1') {que.push({nextx, nexty}); // 压进队列,之后再检查。而不是像DFS一样,一路走到底。(没有BFS的套用)visited[nextx][nexty] = true; // 只要压进队列立刻标记}}}}int numIslands(vector<vector<char>>& grid) {int n = grid.size();int m = grid[0].size();vector<vector<bool>> visited(n, vector<bool>(m, false));int result = 0;for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (!visited[i][j] && grid[i][j] == '1') {visited[i][j] = true;result++; // 结果再进入BFS之前累加,因为找到了新岛屿bfs(grid, visited, i, j); // 将与其链接的岛屿都标记上true}}}return result;}
};
Python深度优先搜索
class Solution:dir = [(0, 1), (1, 0), (0, -1), (-1, 0)]def dfs(self, grid, visited, x, y):for dx, dy in self.dir:nextx, nexty = x + dx, y + dyif nextx < 0 or nextx >= len(grid) or nexty < 0 or nexty >= len(grid[0]):continueif grid[nextx][nexty] == '1' and not visited[nextx][nexty]:visited[nextx][nexty] = Trueself.dfs(grid, visited, nextx, nexty)def numIslands(self, grid: List[List[str]]) -> int:n, m = len(grid), len(grid[0])visited = [[False] * (m) for _ in range(n)]result = 0for i in range(n):for j in range(m):if (grid[i][j] == '1' and not visited[i][j]):result += 1visited[i][j] = Trueself.dfs(grid, visited, i, j)return result