《LeetCode 200 岛屿数量 FloodFill BFS解法》

一.题目

200. 岛屿数量 - 力扣(LeetCode)

二.思路讲解

2.1 思路讲解

本题与 DFS 解法思路一致,只是将深度优先搜索 改为广度优先搜索

  • 遍历整个网格,每遇到一个未访问的陆地'1'),就找到一个新岛屿,计数加 1

  • 然后使用队列 进行 BFS,从该格子出发,向四个方向扩散,将所有相连的陆地标记为已访问(并入队),直到该岛屿的所有格子都被处理。

三.代码演示

cpp 复制代码
class Solution 
{
public:
    int bx[4] = {0,0,1,-1};
    int by[4] = {1,-1,0,0};
    bool check[301][301];
    typedef pair<int,int>PII;
    int row;
    int col;
    int numIslands(vector<vector<char>>& grid) 
    {
        row = grid.size();
        col = grid[0].size();
        int ret = 0;//统计数量


        for(int i = 0;i < row;i++)
        {
            for(int j = 0;j < col;j++)
            {
                if(grid[i][j] == '1' && check[i][j] != true)
                {
                    ret++;
                    bfs(grid,i,j);
                }

            }
        }
        return ret;
    }
    void bfs(vector<vector<char>>& grid,int i,int j)
    {
        queue<PII>q;
        q.push({i,j});
        while(q.size())
        {
            auto [a,b] = q.front();
            q.pop();
            check[a][b] = true;//标记已使用
            for(int k = 0;k < 4;k++)
            {
                int x = a + bx[k],y = b + by[k];
                if(x >= 0 && y >= 0 && x < row && y < col && !check[x][y] && grid[x][y] == '1')
                {
                    check[x][y] = true;
                    q.push({x,y});
                }
            }
        }    
    }
};

四.代码讲解

一、全局变量与数据结构
  • bx[4]by[4]:方向数组,表示上下左右四个方向的偏移量。

  • check[301][301] :布尔数组,标记格子是否已被访问(已属于某个岛屿)。初始值需在函数内清零,此处未显式初始化,但在实际调用中应在 numIslands 开头使用 memsetvector 初始化,避免残留数据影响结果。

  • typedef pair<int,int> PII:简化坐标类型的书写。

  • rowcol:成员变量,存储网格的行数和列数,便于 BFS 中边界判断。

二、主函数 numIslands
  1. 获取网格的行数 row 和列数 col

  2. 初始化结果变量 ret = 0

  3. 双重循环遍历整个网格:

    • 如果当前格子是陆地 '1' 且未被访问过(!check[i][j]),则发现一个新岛屿,ret++,并调用 BFS 函数 bfs(grid, i, j) 将该岛屿的所有陆地标记为已访问。
  4. 遍历结束后返回岛屿总数 ret

三、BFS 函数 bfs

bfs(grid, i, j)(i, j) 为起点,将与其相连的所有陆地标记为已访问。执行流程如下:

  1. 初始化队列 :创建一个队列 q,将起点 (i, j) 入队,并立即标记 check[i][j] = true(避免重复处理)。

  2. 循环处理:当队列不为空时,重复以下步骤:

    • 取出队头坐标 (a, b)(使用 auto [a, b] = q.front(); q.pop(); 结构绑定)。

    • 遍历四个方向,计算新坐标 (x, y)

    • 若新坐标在网格范围内、未被访问(!check[x][y])、且是陆地 '1',则将其标记为已访问(check[x][y] = true),并加入队列。

  3. 队列为空时,该岛屿的所有连通陆地均已处理完毕,函数返回。

四、关键细节
  • 入队即标记:在将邻居加入队列前立即标记为已访问,避免同一格子被多次入队,保证每个格子只被处理一次,提高效率。

  • 边界检查:每次移动前必须检查坐标合法性,防止越界。

五、流程图