floodfill算法(一)

目录

一、图像渲染

[1. 题目链接:733. 图像渲染](#1. 题目链接:733. 图像渲染)

[2. 题目描述:](#2. 题目描述:)

[3. 解法](#3. 解法)

🌴算法思路:

🌴算法代码:

二、岛屿数量

[1. 题目链接:200. 岛屿数量](#1. 题目链接:200. 岛屿数量)

[2. 题目描述:](#2. 题目描述:)

[3. 解法](#3. 解法)

🌴算法思路:

🌴算法流程:

🌴算法代码:

三、岛屿的最大面积

[1. 题目链接:695. 岛屿的最大面积](#1. 题目链接:695. 岛屿的最大面积)

[2. 题目描述:](#2. 题目描述:)

[3. 解法(深搜dfs)](#3. 解法(深搜dfs))

🌴算法思路:

🌴算法流程:

🌴算法代码:

四、被围绕的区域

[1. 题目链接:130. 被围绕的区域](#1. 题目链接:130. 被围绕的区域)

[2. 题目描述:](#2. 题目描述:)

[3. 解法](#3. 解法)

🌴算法思路:

🌴算法代码:


一、图像渲染

1. 题目链接:733. 图像渲染

2. 题目描述:

有一幅以 m x n 的二维整数数组表示的图画 image ,其中 image[i][j] 表示该图画的像素值大小。

你也被给予三个整数 sr , sccolor 。你应该从像素 image[sr][sc] 开始对图像进行 上色填充

为了完成 上色工作 ,从初始像素开始,记录初始坐标的 上下左右四个方向上 相邻且同色的像素点,接着再记录与这些像素点相邻且同色的新像素点,......,重复该过程。将所有有记录的像素点的颜色值改为 color

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

示例 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,因为它不是在上下左右四个方向上与初始点相连的像素点。

示例 2:

复制代码
输入: image = [[0,0,0],[0,0,0]], sr = 0, sc = 0, color = 0
输出: [[0,0,0],[0,0,0]]

提示:

  • m == image.length
  • n == image[i].length
  • 1 <= m, n <= 50
  • 0 <= image[i][j], color < 216
  • 0 <= sr < m
  • 0 <= sc < n

3. 解法

🌴算法思路:

可以利用「深搜」或者「宽搜」,遍历到与该点相连的所有「像素相同的点」,然后将其修改成指定的像素即可。

递归函数设计:

参数:

a. 原始矩阵;

b. 当前所在的位置;

c. 需要修改成的颜色。

函数体:

a. 先将该位置的颜色改成指定颜色(因为我们的判断,保证每次进入递归的位置都是需要修改的位置);

b. 遍历四个方向上的位置:

  • 如果当前位置合法,并且与初始颜色相同,就递归进去。

🌴算法代码:

cpp 复制代码
class Solution 
{
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    int m, n;
    int prev;
public:
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) 
    {
        if (image[sr][sc] == color) return image;

        m = image.size(), n = image[0].size();
        prev = image[sr][sc];
        dfs(image, sr, sc, color);
        return image;
    }
    void dfs(vector<vector<int>>& image, int i, int j, int color)
    {
        image[i][j] = color;

        for (int k = 0; k < 4; k++)
        {
            int x = i + dx[k], y = j + dy[k];
            if (x >= 0 && x < m && y >=0 && y < n && image[x][y] == prev)
            {
                dfs(image, x, y, color);
            }
        }
    }
};

二、岛屿数量

1. 题目链接:200. 岛屿数量

2. 题目描述:

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

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 300
  • grid[i][j] 的值为 '0''1'

3. 解法

🌴算法思路:

遍历整个矩阵,每次找到「⼀块陆地」的时候:

  • 说明找到「⼀个岛屿」,记录到最终结果 ret 里面;
  • 并且将这个陆地相连的所有陆地,也就是这块「岛屿」,全部「变成海洋」。这样的话,我们下次遍历到这块岛屿的时候,它「已经是海洋」了,不会影响最终结果。
  • 其中「变成海洋」的操作,可以利用「深搜」和「宽搜」解决,其实就是 [733. 图像渲染]( "733. 图像渲染") 这道题~

这样,当我们,遍历完全部的矩阵的时候, ret 存的就是最终结果。

🌴算法流程:

  1. 初始化 ret = 0 ,记录目前找到的岛屿数量;
  2. 双重循环遍历二维网格,每当遇到一块陆地,标记这是一个新的岛屿,然后将这块陆地相连的陆地全部变成海洋。

递归函数的设计:

  1. 把当前格子标记为水;

  2. 向上、下、左、右四格递归寻找陆地,只有在下标位置合理的情况下,才会进入递归:

  • 下一个位置的坐标合理;
  • 并且下一个位置是陆地。

🌴算法代码:

cpp 复制代码
class Solution 
{
    vector<vector<bool>> vis;
    int m, n;
public:
    int numIslands(vector<vector<char>>& grid) 
    {
        m = grid.size(), n = grid[0].size();
        vis = vector<vector<bool>>(m, vector<bool>(n));

        int ret = 0;
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
            {
                if (!vis[i][j] && grid[i][j] == '1')
                {
                    ret++;
                    dfs(grid, i, j);
                }
            }
        
        return ret;
    }

    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    void dfs(vector<vector<char>>& grid, int i, int j)
    {
        vis[i][j] = true;
        for (int k = 0; k < 4; k++)
        {
            int x = i + dx[k], y = j + dy[k];
            if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1' && !vis[x][y])
            {
                dfs(grid, x, y);
            }
        }
    }
};

三、岛屿的最大面积

1. 题目链接:695. 岛屿的最大面积

2. 题目描述:

给你一个大小为 m x n 的二进制矩阵 grid

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

岛屿的面积是岛上值为 1 的单元格的数目。

计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0

示例 1:

复制代码
输入: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
解释:答案不应该是 11 ,因为岛屿只能包含水平或垂直这四个方向上的 1 。

示例 2:

复制代码
输入:grid = [[0,0,0,0,0,0,0,0]]
输出:0

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 50
  • grid[i][j]01

3. 解法(深搜dfs)

🌴算法思路:

  1. 遍历整个矩阵,每当遇到⼀块土地的时候,就用「深搜」或者「宽搜」将与这块土地相连的「整个岛屿」的面积计算出来。

  2. 然后在搜索得到的「所有的岛屿面积」求⼀个「最大值」即可。

  3. 在搜索过程中,为了「防止搜到重复的土地」:

  • 可以开一个同等规模的「布尔数组」,标记一下这个位置是否已经被访问过;
  • 也可以将原始矩阵的 1 修改成 0 ,但是这样操作会修改原始矩阵。

🌴算法流程:

主函数内:

a. 遍历整个数组,发现⼀块没有遍历到的土地之后,就用 dfs ,将与这块土地相连的岛屿的面积求出来;

b. 然后将面积更新到最终结果 ret 中。

深搜函数 dfs 中:

a. 能够进到 dfs 函数中,说明是一个没遍历到的位置;

b. 标记一下已经遍历过,设置一个变量 S = 1 (当前这个位置的面积为 1 ),记录最终的面积;

c. 上下左右遍历四个位置:

  • 如果找到⼀块没有遍历到的土地,就将与这块土地相连的岛屿面积累加到 S 上;

d. 循环结束后, S 中存的就是整块岛屿的面积,返回即可。

🌴算法代码:

cpp 复制代码
class Solution 
{
    vector<vector<bool>> vis;
    int m, n;
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    int count;
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) 
    {
        m = grid.size(), n = grid[0].size();
        vis = vector<vector<bool>>(m, vector<bool>(n));

        int ret = 0;
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
            {
                if (!vis[i][j] && grid[i][j] == 1)
                {
                    count = 0;
                    dfs (grid, i, j);
                    ret = max(ret, count);
                }
            }
        
        return ret;
    }
    void dfs (vector<vector<int>>& grid, int i, int j)
    {
        count++;
        vis[i][j] = true;
        for (int k = 0; k < 4; k++)
        {
            int x = i + dx[k], y =  j + dy[k];
            if (x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && grid[x][y] == 1)
            {
                dfs (grid, x, y);
            }
        }
    }
};

四、被围绕的区域

1. 题目链接:130. 被围绕的区域

2. 题目描述:

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

  • **连接:**一个单元格与水平或垂直方向上相邻的单元格连接。
  • 区域:连接所有 'O' 的单元格来形成一个区域。
  • 围绕: 如果您可以用 'X' 单元格 连接这个区域 ,并且区域中没有任何单元格位于 board 边缘,则该区域被 'X' 单元格围绕。

通过将输入矩阵 board 中的所有 '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"]]

解释:

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

示例 2:

**输入:**board = [["X"]]

输出:[["X"]]

提示:

  • m == board.length
  • n == board[i].length
  • 1 <= m, n <= 200
  • board[i][j]'X''O'

3. 解法

🌴算法思路:

正难则反

可以先利用 dfs 将与边缘相连的 '0' 区域做上标记,然后重新遍历矩阵,将没有标记过的 '0' 修改成 'X' 即可。

🌴算法代码:

cpp 复制代码
class Solution 
{
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    int m, n;
public:
    void solve(vector<vector<char>>& board) 
    {
        m = board.size(), n = board[0].size();

        // 1.把与边界相连的连通块 'O' 修改成 '.'
        for (int j = 0; j < n; j++)
        {
            if (board[0][j] == 'O') dfs(board, 0, j);
            if (board[m - 1][j] == 'O') dfs(board, m - 1, j);
        }
        for (int i = 0; i < m; i++)
        {
            if (board[i][0] == 'O') dfs(board, i, 0);
            if (board[i][n - 1] == 'O') dfs(board, i, n - 1);
        }

        // 2.还原
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
            {
                if (board[i][j] == '.') board[i][j] = 'O';
                else if (board[i][j] == 'O') board[i][j] = 'X';
            }
    }
    void dfs(vector<vector<char>>& board, int i, int j)
    {
        board[i][j] = '.';
        for (int k = 0; k < 4; k++)
        {
            int x = i + dx[k], y = j + dy[k];
            if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'O')
            {
                dfs(board, x, y);
            }
        }
    }
};
相关推荐
yuanbenshidiaos8 分钟前
C++----------函数的调用机制
java·c++·算法
唐叔在学习12 分钟前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA32 分钟前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
chengooooooo33 分钟前
代码随想录训练营第二十七天| 贪心理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和
算法·leetcode·职场和发展
jackiendsc40 分钟前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
游是水里的游2 小时前
【算法day20】回溯:子集与全排列问题
算法
yoyobravery2 小时前
c语言大一期末复习
c语言·开发语言·算法
Jiude2 小时前
算法题题解记录——双变量问题的 “枚举右,维护左”
python·算法·面试
被AI抢饭碗的人2 小时前
算法题(13):异或变换
算法
nuyoah♂3 小时前
DAY36|动态规划Part04|LeetCode:1049. 最后一块石头的重量 II、494. 目标和、474.一和零
算法·leetcode·动态规划