BFS-FloodFill 算法 解决最短路问题 多源 解决拓扑排序


文章目录

  • 一、FloodFill 算法
  • [733. 图像渲染](https://leetcode.cn/problems/flood-fill/description/)
    • 2.思路
    • 3.代码
  • [200. 岛屿数量](https://leetcode.cn/problems/number-of-islands/description/)
    • 2.思路
    • 3.代码
  • [LCR 105. 岛屿的最大面积](https://leetcode.cn/problems/ZL6zAn/description/)
    • 2.思路
    • 3.代码
  • [130. 被围绕的区域](https://leetcode.cn/problems/surrounded-regions/description/)
    • 2.思路
    • 3.代码
  • 二、最短路径
  • [1926. 迷宫中离入口最近的出口](https://leetcode.cn/problems/nearest-exit-from-entrance-in-maze/description/)
    • 2.思路
    • 3.代码
  • [433. 最小基因变化](https://leetcode.cn/problems/minimum-genetic-mutation/description/)
    • 2.思路
    • 3.代码
  • [LCR 108. 单词接龙](https://leetcode.cn/problems/om3reC/description/)
    • 2.思路
    • 3.代码
  • [675. 为高尔夫比赛砍树](https://leetcode.cn/problems/cut-off-trees-for-golf-event/description/)-hard待研究
    • 2.思路
    • 3.代码
  • 三、多源 BFS
  • [LCR 107. 01 矩阵](https://leetcode.cn/problems/2bCMpM/description/)
    • 2.思路
    • 3.代码
  • [1020. 飞地的数量](https://leetcode.cn/problems/number-of-enclaves/description/)
    • 2.思路
    • 3.代码
  • [1765. 地图中的最高点](https://leetcode.cn/problems/map-of-highest-peak/description/)
    • 2.思路
    • 3.代码
  • [1162. 地图分析](https://leetcode.cn/problems/as-far-from-land-as-possible/description/)
    • 2.思路
    • 3.代码
  • 四、拓扑排序
  • [207. 课程表](https://leetcode.cn/problems/course-schedule/description/)
    • 2.思路
    • 3.代码
  • [210. 课程表 II](https://leetcode.cn/problems/course-schedule-ii/description/)
    • 2.思路
    • 3.代码
  • [LCR 114. 火星词典](https://leetcode.cn/problems/Jf1JuT/description/)-hard待研究
    • 2.思路
        • 示例解释
    • 3.代码


一、FloodFill 算法

洪水灌溉,可以用BFS也可以用DFS

//辅助数组visited中存放所有节点
//初始化为0,访问过后设置为1 
void BFS (Graph G, int v){		//按广度优先非递归遍历连通图G
	cout< q;				//辅助队列Q初始化,置空
	q.push(v);				//v进队
	while(!q.empty()){ 		//队列非空
		q.pop();			//队头元素出队并置为u
		for (int i = 0; i < G.vexnum; i++) {
			int w = G.vex[i];
			if (G.edge[k][i] && !visited[i]) {//v和i有边且没有被访问
				cout << w;
				q.push(w);
				visited[i] = 1;
			}
		}
	}
}
//调用
void BFStraverse(graph) {
	for (int v = 0; v < G.vexnum; ++v)
		visited[v] = 0;
	for (int v = 0; v < G.vexnum; ++v)
		if (!visited[v])
			BFS(G, G.vex[v]);
}


733. 图像渲染

有一幅以 m x n 的二维整数数组表示的图画 image ,其中 image[i][j] 表示该图画的像素值大小。你也被给予三个整数 sr , sccolor 。你应该从像素 image[sr][sc] 开始对图像进行上色 填充

为了完成 上色工作

- 从初始像素开始,将其颜色改为 `color`。

- 对初始坐标的 **上下左右四个方向上** 相邻且与初始像素的原始颜色同色的像素点执行相同操作。

- 通过检查与初始像素的原始颜色相同的相邻像素并修改其颜色来继续 **重复** 此过程。

- 当 **没有** 其它原始颜色的相邻像素时 **停止** 操作。

最后返回经过上色渲染 修改 后的图像 。

示例 1:

BFS-FloodFill 算法 解决最短路问题 多源 解决拓扑排序_第1张图片

**输入:**image = [[1,1,1],[1,1,0],[1,0,1]],sr = 1, sc = 1, color = 2

输出:[[2,2,2],[2,2,0],[2,0,1]]

解释:在图像的正中间,坐标 (sr,sc)=(1,1) (即红色像素),在路径上所有符合条件的像素点的颜色都被更改成相同的新颜色(即蓝色像素)。

注意,右下角的像素 没有 更改为2,因为它不是在上下左右四个方向上与初始点相连的像素点。

示例 2:

**输入:**image = [[0,0,0],[0,0,0]], sr = 0, sc = 0, color = 0

输出:[[0,0,0],[0,0,0]]

**解释:**初始像素已经用 0 着色,这与目标颜色相同。因此,不会对图像进行任何更改。

2.思路

使用一个队列来存储待处理的像素点,将起始点加入队列并将其颜色替换为目标颜色,然后不断从队列中取出像素点,检查其上下左右相邻的像素点,如果相邻像素点的颜色与起始点的原始颜色相同,则将其颜色替换为目标颜色并加入队列,直到队列为空

3.代码

class Solution {
public:
    // BFS 函数用于执行广度优先搜索,对图像中与起始点颜色相同且相连通的区域进行颜色替换
    void BFS(std::vector>& image, int sr, int sc, int currColor, int color) {
        // 定义一个队列,用于存储待处理的像素点,每个像素点用一个 std::pair 表示,分别代表行和列
        std::queue> q;
        // 将起始点加入队列
        q.push({sr, sc});
        // 立即将起始点的颜色替换为目标颜色,避免后续重复处理该点
        image[sr][sc] = color;

        // 当队列不为空时,继续处理队列中的像素点
        while (!q.empty()) {
            // 取出队列头部的像素点
            int x = q.front().first, y = q.front().second;
            // 将该像素点从队列中移除
            q.pop();

            // 检查当前像素点左侧的像素点
            if (y - 1 >= 0 && image[x][y - 1] == currColor) {
                // 若左侧像素点存在且颜色与起始点的原始颜色相同
                // 将其颜色替换为目标颜色
                image[x][y - 1] = color;
                // 将该像素点加入队列,以便后续处理其相邻像素点
                q.push({x, y - 1});
            }

            // 检查当前像素点右侧的像素点
            if (y + 1 < image[0].size() && image[x][y + 1] == currColor) {
                // 若右侧像素点存在且颜色与起始点的原始颜色相同
                // 将其颜色替换为目标颜色
                image[x][y + 1] = color;
                // 将该像素点加入队列,以便后续处理其相邻像素点
                q.push({x, y + 1});
            }

            // 检查当前像素点上方的像素点
            if (x - 1 >= 0 && image[x - 1][y] == currColor) {
                // 若上方像素点存在且颜色与起始点的原始颜色相同
                // 将其颜色替换为目标颜色
                image[x - 1][y] = color;
                // 将该像素点加入队列,以便后续处理其相邻像素点
                q.push({x - 1, y});
            }

            // 检查当前像素点下方的像素点
            if (x + 1 < image.size() && image[x + 1][y] == currColor) {
                // 若下方像素点存在且颜色与起始点的原始颜色相同
                // 将其颜色替换为目标颜色
                image[x + 1][y] = color;
                // 将该像素点加入队列,以便后续处理其相邻像素点
                q.push({x + 1, y});
            }
        }
    }

    // floodFill 函数是对外提供的接口,用于调用 BFS 函数完成图像填充操作
    std::vector> floodFill(std::vector>& image, int sr, int sc, int color) {
        // 获取起始点的当前颜色
        int currColor = image[sr][sc];
        // 若起始点的当前颜色与目标填充颜色不同,则调用 BFS 函数进行填充
        if (currColor != color) {
            BFS(image, sr, sc, currColor, color);
        }
        // 返回填充后的图像
        return image;
    }
};

200. 岛屿数量

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

2.思路

遍历整个二维数组,返回有多少个完全被0隔开的岛屿1。广度优先搜索的过程,只要队列不为空,就从队列中取出一个位置的坐标。针对这个位置,检查其上下左右四个相邻位置。若相邻位置在网格范围内、值为 '1' 且未被访问过,就将该相邻位置的坐标加入队列,并标记为已访问。通过这种方式,不断扩展当前岛屿所覆盖的范围,直至队列为空,意味着当前岛屿的所有位置都已被访问过。visited默认是 false

3.代码

class Solution {
public:
    bool visited[301][301];
    int numIslands(vector>& grid) {
        queue> q;
        int r = grid.size();
        int c = grid[0].size();
        int ret = 0;
        for (int i = 0; i < r; ++i) {
            for (int j = 0; j < c; ++j) {
                if (grid[i][j] == '1' && visited[i][j] == false) {
                    ret++;
                    q.push({i, j});
                    visited[i][j] = true;
                    while (!q.empty()) {
                        int x = q.front().first, y = q.front().second;
                        q.pop();
                        if(y-1>=0 && grid[x][y-1] == '1' && visited[x][y-1] == false){
                            q.push({x, y-1});
                            visited[x][y-1] = true;
                        }
                        if(y+1=0 && grid[x-1][y] == '1' && visited[x-1][y] == false){
                            q.push({x-1, y});
                            visited[x-1][y] = true;
                        }
                        if(x+1

LCR 105. 岛屿的最大面积

给定一个由 01 组成的非空二维数组 grid ,用来表示海洋岛屿地图。

一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。

找到给定的二维数组中最大的岛屿面积。如果没有岛屿,则返回面积为 0

示例 1:

BFS-FloodFill 算法 解决最短路问题 多源 解决拓扑排序_第2张图片

**输入: **grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
**输出: **6
**解释: **对于上面这个给定矩阵应返回 `6`。注意答案不应该是 `11` ,因为岛屿只能包含水平或垂直的四个方向的 `1` 。

示例 2:

**输入: **grid = [[0,0,0,0,0,0,0,0]]
**输出: **0

2.思路

初始化相关变量:定义一个 visited 二维布尔数组,用于标记网格中每个位置是否已被访问;获取网格的行数和列数;创建一个队列用于 BFS;初始化最大岛屿面积为 0。

遍历网格:使用两层嵌套的 for 循环遍历整个网格。对于每个未被访问且值为 1(表示陆地)的位置,将其标记为已访问,并将其作为一个新岛屿的起始点。

BFS 搜索当前岛屿:将起始点加入队列,开始 BFS 过程。在 BFS 中,从队列中取出一个位置,检查其上下左右四个相邻位置。若相邻位置合法(在网格范围内)、为陆地且未被访问过,则将该相邻位置标记为已访问,岛屿面积加 1,并将其加入队列继续搜索。

更新最大岛屿面积:当当前岛屿的 BFS 搜索结束后,将该岛屿的面积与之前记录的最大岛屿面积进行比较,取较大值更新最大岛屿面积。

3.代码

class Solution {
public:
    // 用于标记网格中每个位置是否被访问过的二维数组
    bool visited[51][51];

    int maxAreaOfIsland(std::vector>& grid) {
        // 获取网格的行数
        int r = grid.size();
        // 获取网格的列数
        int c = grid[0].size();
        // 定义一个队列,用于广度优先搜索(BFS),存储待处理的网格位置
        std::queue> q;
        // 用于记录最大岛屿面积
        int ret = 0;

        // 遍历网格的每一行
        for (int i = 0; i < r; ++i) {
            // 遍历网格的每一列
            for (int j = 0; j < c; ++j) {
                // 如果当前位置未被访问过且为陆地(值为 1)
                if (!visited[i][j] && grid[i][j] == 1) {
                    // 标记当前位置为已访问
                    visited[i][j] = true;
                    // 初始化当前岛屿的面积,起始点面积为 1
                    int sum = 1;
                    // 将当前位置加入队列,准备进行 BFS
                    q.push({i, j});

                    // 开始 BFS 过程,只要队列不为空,就继续处理
                    while (!q.empty()) {
                        // 获取队列头部元素的行和列坐标
                        int x = q.front().first, y = q.front().second;
                        // 从队列中移除头部元素
                        q.pop();

                        // 检查当前位置左侧的位置
                        if (y - 1 >= 0 && grid[x][y - 1] == 1 && !visited[x][y - 1]) {
                            // 若左侧位置合法、为陆地且未被访问过,当前岛屿面积加 1
                            sum++;
                            // 标记左侧位置为已访问
                            visited[x][y - 1] = true;
                            // 将左侧位置加入队列
                            q.push({x, y - 1});
                        }

                        // 检查当前位置右侧的位置
                        if (y + 1 < c && grid[x][y + 1] == 1 && !visited[x][y + 1]) {
                            // 若右侧位置合法、为陆地且未被访问过,当前岛屿面积加 1
                            sum++;
                            // 标记右侧位置为已访问
                            visited[x][y + 1] = true;
                            // 将右侧位置加入队列
                            q.push({x, y + 1});
                        }

                        // 检查当前位置上方的位置
                        if (x - 1 >= 0 && grid[x - 1][y] == 1 && !visited[x - 1][y]) {
                            // 若上方位置合法、为陆地且未被访问过,当前岛屿面积加 1
                            sum++;
                            // 标记上方位置为已访问
                            visited[x - 1][y] = true;
                            // 将上方位置加入队列
                            q.push({x - 1, y});
                        }

                        // 检查当前位置下方的位置
                        if (x + 1 < r && grid[x + 1][y] == 1 && !visited[x + 1][y]) {
                            // 若下方位置合法、为陆地且未被访问过,当前岛屿面积加 1
                            sum++;
                            // 标记下方位置为已访问
                            visited[x + 1][y] = true;
                            // 将下方位置加入队列
                            q.push({x + 1, y});
                        }
                    }
                    // 更新最大岛屿面积
                    ret = std::max(ret, sum);
                }
            }
        }
        // 返回最大岛屿面积
        return ret;
    }
};

130. 被围绕的区域

给你一个 m x n 的矩阵 board ,由若干字符 'X''O' 组成,捕获 所有 被围绕的区域

- **连接:**一个单元格与水平或垂直方向上相邻的单元格连接。

- **区域:连接所有 **`'O'` 的单元格来形成一个区域。

- **围绕:**如果您可以用 `'X'` 单元格 **连接这个区域**,并且区域中没有任何单元格位于 `board` 边缘,则该区域被 `'X'` 单元格围绕。

通过 原地 将输入矩阵中的所有 'O' 替换为 'X'捕获被围绕的区域。你不需要返回任何值。

示例 1:

**输入:**board = [[“X”,“X”,“X”,“X”],[“X”,“O”,“O”,“X”],[“X”,“X”,“O”,“X”],[“X”,“O”,“X”,“X”]]

输出:[[“X”,“X”,“X”,“X”],[“X”,“X”,“X”,“X”],[“X”,“X”,“X”,“X”],[“X”,“O”,“X”,“X”]]

解释:

BFS-FloodFill 算法 解决最短路问题 多源 解决拓扑排序_第3张图片

在上图中,底部的区域没有被捕获,因为它在 board 的边缘并且不能被围绕。

示例 2:

**输入:**board = [[“X”]]

输出:[[“X”]]

2.思路

注意是X和O不是数字0,。

找出边界上的 'O':遍历矩阵的四条边界,将边界上的 'O' 加入队列,并标记为已访问。

广度优先搜索(BFS):从队列中的边界 'O' 开始进行 BFS 遍历,将与这些边界 'O' 相连的所有 'O' 都标记为已访问。

替换未标记的 'O':遍历整个矩阵,将未被标记为已访问的 'O' 替换为 'X'

3.代码

class Solution {
public:
    // 用于标记矩阵中每个位置是否已被访问
    bool visited[201][201];
    void solve(std::vector>& board) {
        // 获取矩阵的行数
        int r = board.size();
        // 如果矩阵为空,直接返回
        if (r == 0) return;
        // 获取矩阵的列数
        int c = board[0].size();
        // 用于进行广度优先搜索(BFS)的队列,存储位置信息
        std::queue> q;

        // 第一步:将边界上的 'O' 加入队列并标记为已访问
        // 遍历矩阵的左右边界
        for (int i = 0; i < r; ++i) {
            // 检查左边界的元素是否为 'O' 且未被访问过
            if (boa

你可能感兴趣的:(#,BFS,算法,宽度优先,leetcode)