【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为例:

每个位置只要是1,先要把它置为0,然后沿着他的上下左右4个方向继续遍历,执行同样的操作,要注意边界条件的判断。

BFS解决方式:

        深度优先搜索(DFS)是一种沿着一条路径不断深入的搜索策略,直到遇到终止条件时才会返回。而广度优先搜索(BFS)则是先访问当前位置附近的节点,就像一个不断扩大的圈,先访问圈内的节点,然后再逐步扩大圈的范围继续访问。如下:

这题使用BFS和DFS都能解决,如果遇到位置为1的格子,只要能把他们挨着的为1的全部置为0,然后挨着的挨着的为1的位置也置为0,然后……一直这样循环下去。

三、代码实现

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攻城狮7号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值