【4.4】图搜索算法-BFS和DFS两种方式解岛屿数量
一、题目
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:
[
[ '1' , '1' , '1' , '1' , ' 0 ' ] ,
[ '1' , '1' , ' 0 ' , ' 1' , ' 0 ' ] ,
[ '1' , '1' , ' 0 ' , ' 0 ' , ' 0 ' ] ,
[ ' 0 ' , ' 0 ' , ' 0 ' , ' 0 ' , ' 0 ' ]
]
输出: 1
示例 2:
输入:
[
[ '1' , '1' , ' 0 ' , ' 0 ' , ' 0 ' ] ,
[ '1' , '1' , ' 0 ' , ' 0 ' , ' 0 ' ] ,
[ ' 0 ' , ' 0 ' , '1' , ' 0 ' , ' 0 ' ] ,
[ ' 0 ' , ' 0 ' , ' 0 ' , ' 1' , '1' ]
]
输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。
二、解题思路
DFS解决方式:
这道题目要求我们计算岛屿的面积,二维数组中值为1的元素表示岛屿。如果多个1是连在一起的,那么它们只能算作一个岛屿。
最简单的方法是遍历数组中的每一个元素,如果遇到1,说明这是一个岛屿,然后将其置为0(或其他非1的字符),接着遍历其上下左右四个位置。如果这些位置中也有1,说明这些岛屿是相连的,只能算作一个岛屿,我们同样将其置为0,然后再以这些位置为中心,继续遍历它们的上下左右四个位置。如果遇到0,说明这不是岛屿,就不再继续向其上下左右四个位置遍历。以示例1为例:
BFS解决方式:
深度优先搜索(DFS)是一种沿着一条路径不断深入的搜索策略,直到遇到终止条件时才会返回。而广度优先搜索(BFS)则是先访问当前位置附近的节点,就像一个不断扩大的圈,先访问圈内的节点,然后再逐步扩大圈的范围继续访问。如下:
三、代码实现
DFS方式:
#include <iostream>
#include <vector>
using namespace std;
void dfs(vector<vector<char>>& grid, int i, int j) {
// 边界条件判断,不能越界
if (i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size() || grid[i][j] == '0')
return;
// 把当前格子置为0,然后再从他的上下左右4个方向继续遍历
grid[i][j] = '0';
dfs(grid, i - 1, j); // 上
dfs(grid, i + 1, j); // 下
dfs(grid, i, j - 1); // 左
dfs(grid, i, j + 1); // 右
}
int numIslands(vector<vector<char>>& grid) {
// 边界条件判断
if (grid.empty() || grid[0].empty())
return 0;
int count = 0;
// 两个for循环遍历每一个格子
for (int i = 0; i < grid.size(); i++) {
for (int j = 0; j < grid[0].size(); j++) {
// 只有当前格子是1才开始计算
if (grid[i][j] == '1') {
// 如果当前格子是1,岛屿的数量加1
count++;
// 然后通过dfs把当前格子的上下左右4个位置为1的都要置为0,因为他们是连在一起的算一个岛屿
dfs(grid, i, j);
}
}
}
// 最后返回岛屿的数量
return count;
}
int main() {
vector<vector<char>> grid = {
{'1', '1', '0', '0', '0'},
{'1', '1', '0', '0', '0'},
{'0', '0', '1', '0', '0'},
{'0', '0', '0', '1', '1'}
};
int result = numIslands(grid);
cout << "Number of islands: " << result << endl;
return 0;
}
BFS方式:
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
void bfs(vector<vector<char>>& grid, int x, int y) {
int n = grid.size();
int m = grid[0].size();
queue<int> queue;
// 把当前格子先置为0
grid[x][y] = '0';
// 把两位数字转化为一位数字并存放到队列中
int code = x * m + y;
queue.push(code);
while (!queue.empty()) {
// 出队
code = queue.front();
queue.pop();
// 反转成坐标值(i,j)
int i = code / m;
int j = code % m;
// 上
if (i > 0 && grid[i - 1][j] == '1') {
grid[i - 1][j] = '0';
queue.push((i - 1) * m + j);
}
// 下
if (i < n - 1 && grid[i + 1][j] == '1') {
grid[i + 1][j] = '0';
queue.push((i + 1) * m + j);
}
// 左
if (j > 0 && grid[i][j - 1] == '1') {
grid[i][j - 1] = '0';
queue.push(i * m + j - 1);
}
// 右
if (j < m - 1 && grid[i][j + 1] == '1') {
grid[i][j + 1] = '0';
queue.push(i * m + j + 1);
}
}
}
int numIslands(vector<vector<char>>& grid) {
// 边界条件判断
if (grid.empty() || grid[0].empty())
return 0;
int count = 0;
// 两个for循环遍历每一个格子
for (int i = 0; i < grid.size(); i++) {
for (int j = 0; j < grid[0].size(); j++) {
// 只有当前格子是1才开始计算
if (grid[i][j] == '1') {
// 如果当前格子是1,岛屿的数量加1
count++;
// 然后通过bfs把当前格子的上下左右4个位置为1的都要置为0,因为他们是连在一起的算一个岛屿
bfs(grid, i, j);
}
}
}
return count;
}
int main() {
vector<vector<char>> grid = {
{'1', '1', '0', '0', '0'},
{'1', '1', '0', '0', '0'},
{'0', '0', '1', '0', '0'},
{'0', '0', '0', '1', '1'}
};
int result = numIslands(grid);
cout << "Number of islands: " << result << endl;
return 0;
}