floodfill 算法(上)

目录

图像渲染

题意:

题解:

非递归:

递归:

岛屿数量

题解:

非递归:

递归:

岛屿的最大面积

题解:

非递归:

递归:

 被围绕的区域

题解:

非递归:

递归: 


图像渲染

733. 图像渲染 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/flood-fill/description/

题意:

把初始位置的颜色作为标准值,如果其上下左右位置的颜色和标准值相同,就把该位置的颜色更改为 newColor,接着继续往外扩,重复上述操作。

题解:

这种题的思想类似树的层序遍历,我们从指定的坐标出发,查看上下左右的颜色,相当于查看外面一层的颜色,把需要染色的位置染色后,继续查看该位置外面一层的颜色。

思想类似,代码也类似。

我们定义一个队列,队列中存储需要修改颜色的位置的下标,便于层序遍历,先把初始位置入队:

1、取出队头 t ,并删除队头,接着修改 t 的颜色;

2、判断 t 的上、下、左、右是否需要修改颜色,如果需要修改,则把对应的位置入队;

3、在数组中,假设 t 的下标为 (x,y),那么其上下左右的下标如图:

为了便于访问上下左右的位置,我们定义 dx、dy 数组,dx、dy 的同一个位置,对应着相对于 t 下标的偏移量,比如 t 的右边,可以看作 x 位置不变(相当于偏移了 0 个单位),y 向右偏移 1 个单位(+1),t 的左边,可以看作 x 位置不变,y 向左偏移 1 个单位(-1)。

int dx[4]={0,0,1,-1};//分别对应右、左、下、上
int dy[4]={1,-1,0,0};

我们只需要用 for 循环同时遍历这两个数组,就可以获得偏移量来计算上下左右的下标,但是这样的计算存在数组越界的风险,所以计算后的结果需要判断是否越界! 

该算法会对同一个位置重复访问:

1、对于不需要修改颜色的位置,即使多次访问也不会修改颜色,并不影响最终结果;

2、对于需要修改颜色的位置,第一次访问时,已经更改颜色,所以颜色和 std 不一样了,后序再次访问,已经变成情况 1 了,不会再次更改颜色。

非递归:

class Solution {
public:
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {
        int std=image[sr][sc];
        if(std==color) return image;

        int dx[4]={0,0,1,-1};//分别对应右、左、下、上
        int dy[4]={1,-1,0,0};
        int m=image.size(),n=image[0].size();

        queue<pair<int,int>> q;
        q.push({sr,sc});

        while(!q.empty())
        {
            auto [x,y]=q.front();
            q.pop();
            image[x][y]=color;//修改像素
            for(int i=0;i<4;i++)
            {
                int x1=x+dx[i],y1=y+dy[i];//存入上下左右
                if(x1>=0 && x1<m && y1>=0 && y1<n && image[x1][y1]==std)
                {
                    q.push({x1,y1});
                }    
            }
        }

        return image;
    }
};

递归:

递归算法相当于在找需要修改颜色的下标时,一直向同一个方向递归,可以是一直向左、一直向右、一直向下、一直向上递归,直到这个颜色是不需要修改时,不再递归,再去判断其他方向是否需要修改颜色。

class Solution {
public:
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {
        if(image[sr][sc]==color) return image;
        int std=image[sr][sc];

        dfs(image,sr,sc,color,std);
        return image;
    }
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    void dfs(vector<vector<int>>& image, int i, int j, int color,int std)
    {
        //修改当前格
        image[i][j]=color;
        for(int k=0;k<4;k++)
        {
            int x=i+dx[k],y=j+dy[k];
            //修改上下左右
            if(x>=0 && x<image.size() && y>=0 && y<image[0].size() && image[x][y] ==std)
                dfs(image,x,y,color,std);
        }

    }
};

岛屿数量

200. 岛屿数量 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/number-of-islands/description/

题解:

图像渲染是一个点不断向外扩展,这道题是多个点不断向外扩展,需要记录一共有多少个点源向外扩展了。

我们用两层 for 循环遍历数组,如果遍历到的位置是陆地,由于题目定义岛屿被水围绕,所以我们需要不断扩展,直到周围都是水,才停止扩展,此时岛屿数量+1。图像渲染即使对同一个位置重复访问也不会影响结果,而这道题同一个位置重复访问,结果会出现很大的错误!

以示例 1 为例,如左图,当我们访问 grid[ 0 ][ 0 ] 时,该位置为陆地,我们不断扩展,岛屿数量+1,当我们访问  grid[ 0 ][ 1 ] 时,该位置是陆地,但当前访问的陆地和上一次访问的陆地属于同一座岛屿,不能被认为是新的岛屿了!

我们设置一个和 grid 同等规模的 bool 类型的数组 vis,用于标记该陆地是否为未被发现的岛屿。

1、当 grid[ i ][ j ] 为陆地时,查看 vis[ i ][ j ] 的bool 值:

a. vis[ i ][ j ] 为 true,是已经被发现的岛屿,该陆地不可以被记为岛屿;

b. vis[ i ][ j ] 为 false,是未被发现的岛屿,可以记为新的岛屿,并且向外扩展,把相连的陆地的 vis 全部记为 true,直到周围都是水为止。

2、当 grid[ i ][ j ] 为水时,不需要做任何处理。

扩展的思路和图像渲染一样,这里不再赘述。

非递归:

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        int m=grid.size(),n=grid[0].size();
        vector<vector<bool>> vis(m,vector<bool>(n));
        int ret=0;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(grid[i][j]=='1' && !vis[i][j])
                {
                    ret++;
                    bfs(grid,vis,i,j,m,n);
                }
            }
        }
        return ret;
    }
    void bfs(vector<vector<char>>& grid,vector<vector<bool>>& vis,int i,int j,int m,int n)
    {
        int dx[4]={0,0,1,-1};
        int dy[4]={1,-1,0,0};
        queue<pair<int,int>> q;
        q.push({i,j});

        while(!q.empty())
        {
            auto [a,b]=q.front();
            q.pop();
            for(int k=0;k<4;k++)
            {
                int x=a+dx[k],y=b+dy[k];
                if(x>=0 && x<m && y>=0 && y<n && grid[x][y]=='1' && !vis[x][y])
                {
                    q.push({x,y});
                    vis[x][y]=true;
                }
            }
        }
    }
};

递归:

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        vector<vector<bool>> vis(grid.size(),vector<bool> (grid[0].size()));

        int ret=0;
        for(int i=0;i<grid.size();i++)
        {
            for(int j=0;j<grid[0].size();j++)
            {
                if(grid[i][j]=='1' && !vis[i][j])
                {
                    ++ret;
                    dfs(grid,vis,i,j);
                }
            }
        }
        return ret;
    }
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    void dfs(vector<vector<char>>& grid,vector<vector<bool>>& vis,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<grid.size() && y>=0 && y<grid[0].size() && grid[x][y]=='1'&& !vis[x][y] )
                dfs(grid,vis,x,y);
        }
    }
};

岛屿的最大面积

695. 岛屿的最大面积 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/max-area-of-island/description/

题解:

这道题只需要在每次扩展岛屿的陆地时,记录一共扩展了多少块陆地即可,同理对已经被发现的陆地,不可以重复计算。 

非递归:

class Solution {
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int ret=0,m=grid.size(),n=grid[0].size();
        vector<vector<bool>> vis(m,vector<bool>(n));
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(grid[i][j]==1 && !vis[i][j])
                {
                    int tmp=AreaOfIsland(grid,i,j,vis);
                    ret=max(ret,tmp);
                }
            }
        }
        return ret;        
    }

    int AreaOfIsland(vector<vector<int>>& grid,int i,int j,vector<vector<bool>>& vis)
    {
        int dx[4]={0,0,1,-1};
        int dy[4]={1,-1,0,0};
        queue<pair<int,int>> q;
        q.push({i,j});
        int area=1;
        //++area;
        vis[i][j]=true;
        while(!q.empty())
        {
            auto [a,b]=q.front();
            q.pop();
            for(int k=0;k<4;k++)
            {
                int x=a+dx[k],y=b+dy[k];
                if(x>=0 && x<grid.size() && y>=0 && y<grid[0].size() && grid[x][y]==1 && !vis[x][y])
                {
                    q.push({x,y});
                    vis[x][y]=true;
                    ++area;
                }
            }
        }
        return area;
    } 
};

递归:

class Solution {
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        vector<vector<bool>> vis(grid.size(),vector<bool>(grid[0].size()));
        int ret=0;
        for(int i=0;i<grid.size();i++)
        {
            for(int j=0;j<grid[0].size();j++)
            {
                if(grid[i][j]==1 && !vis[i][j])
                {
                    int tmp=0;
                    dfs(grid,vis,i,j,tmp);
                    ret=max(ret,tmp);
                }
            }
        }
        return ret;
    }

    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    void dfs(vector<vector<int>>& grid,vector<vector<bool>>& vis,int i,int j,int& area)
    {
        ++area;        
        vis[i][j]=true;//修改当前值
        for(int k=0;k<4;k++)
        {
            int x=i+dx[k],y=j+dy[k];
            if(x>=0 && x<grid.size() && y>=0 && y<grid[0].size() && grid[x][y]==1 && !vis[x][y])
                dfs(grid,vis,x,y,area);
        }        
    }
};

 被围绕的区域

130. 被围绕的区域 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/surrounded-regions/description/

题解:

本道题和图像渲染类似,但是如果区域内的 O 与边界的 O 相连,那么这个 O 不可以被修改!这个特殊条件并不好处理。

1、我们可以优先处理和边界相连的 O

可以设置一个和 board 相同规模的 bool类型的数组 vis,把和边界相连的 O 的对应位置的 vis 设置为 true。

2、用两层 for 循环遍历 board:

a. 如果 board[ i ][ j ] 为 O,且 vis[ i ][ j ] 为 false,说明这个 O 没有和边界的 O 相连,把它修改为 X;

b. 如果 board[ i ][ j ] 为 O,且 vis[ i ][ j ] 为 true,说明这个 O 和边界的 O 相连,不需要修改;

c. 如果 board[ i ][ j ] 为 X,不需要做任何处理。

非递归:

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

        vector<vector<bool>> vis(m,vector<bool>(n));

        for(int i=0;i<n;i++)
        {
            if(board[0][i]=='O' && !vis[0][i])//第一行
                SetVisO(board,vis,0,i);
            if(board[m-1][i]=='O' && !vis[m-1][i])//最后一行
                SetVisO(board,vis,m-1,i);
        }

        for(int i=1;i<m-1;i++)
        {
            if(board[i][0]=='O' && !vis[i][0])//第一列
                SetVisO(board,vis,i,0);
            if(board[i][n-1]=='O' && !vis[i][n-1])//最后一列
                SetVisO(board,vis,i,n-1);
        }

        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(board[i][j]=='O' && !vis[i][j])
                    board[i][j]='X';
            }
        }
    }
   
    //处理边界的O
    void SetVisO(vector<vector<char>>& board,vector<vector<bool>>& vis,int i,int j)
    {
        queue<pair<int,int>> q;
        q.push({i,j});
        vis[i][j]=true;//处理当前位置
        while(!q.empty())
        {
            auto [a,b]=q.front();
            q.pop();
            for(int k=0;k<4;k++)//处理上下左右位置
            {
                int x=a+dx[k],y=b+dy[k];
                if(x>=0 && x<m && y>=0 && y<n && board[x][y]=='O' && !vis[x][y])
                {
                    vis[x][y]=true;
                    q.push({x,y});
                }
            }
        }
    }
};

递归: 

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

        vector<vector<bool>> vis(m,vector<bool>(n));

        for(int i=0;i<n;i++)
        {
            if(board[0][i]=='O' && !vis[0][i])//第一行
                SetVisO(board,vis,0,i);
            if(board[m-1][i]=='O' && !vis[m-1][i])//最后一行
                SetVisO(board,vis,m-1,i);
        }

        for(int i=1;i<m-1;i++)
        {
            if(board[i][0]=='O' && !vis[i][0])//第一列
                SetVisO(board,vis,i,0);
            if(board[i][n-1]=='O' && !vis[i][n-1])//最后一列
                SetVisO(board,vis,i,n-1);
        }

        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(board[i][j]=='O' && !vis[i][j])//根据O的状态来判断是否修改
                    board[i][j]='X';
            }
        }
    }

    //处理边界的O
    void SetVisO(vector<vector<char>>& board,vector<vector<bool>>& vis,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<board.size() && y>=0 && y<vis[0].size() && board[x][y]=='O'&&!vis[x][y])
                SetVisO(board,vis,x,y);
        }
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/655049.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

10G SFP双口万兆以太网控制器,高速光口网络接口卡

2-Port 10G SFP NIC 是一款高速网 络接口卡&#xff0c;采用了 PCI Express 3.0 x8 接口&#xff0c;支持双 端口万兆以太网&#xff0c;具有高性能、高可靠性、低功耗等 优点&#xff0c;是数据中心、云计算、虚拟化等领域的理想选 择。 支持多种网络协议&#xff0c;如 …

爱岗敬业短视频:成都科成博通文化传媒公司

爱岗敬业短视频&#xff1a;传递正能量&#xff0c;塑造职场新风尚 在当今社会&#xff0c;短视频以其独特的传播方式和广泛的受众群体&#xff0c;成为了信息传播的重要渠道。在众多短视频内容中&#xff0c;以“爱岗敬业”为主题的短视频尤为引人注目&#xff0c;成都科成博…

云衔科技:为什么推荐使用zoho crm客户管理系统?

在当今快速变化的商业环境中&#xff0c;企业对高效、智能化的客户关系管理&#xff08;CRM&#xff09;系统的需求日益增长。Zoho CRM&#xff0c;作为全球领先的企业级CRM解决方案提供商&#xff0c;凭借其全面的功能、高度的可定制性、以及无缝集成的生态系统&#xff0c;成…

无人机河道巡查方案,智能巡检助力水域监管革新

无人机技术的飞速发展为河道监管工作带来了创新的解决方案。无人机河道巡查以其高效、精准、智能的特点&#xff0c;正在逐步替代传统河道巡检方式&#xff0c;为水域管理提供了强有力的技术支持。 一、自主巡逻&#xff0c;提升河道监管效率 无人机河道巡查搭载先进的控制装置…

AI图书推荐:终极ChatGPT企业手册—借助Python和Java实现

《终极ChatGPT企业手册—借助Python和Java实现》&#xff08;Ultimate ChatGPT Handbook for Enterprises&#xff09;是一本关于ChatGPT的手册&#xff0c;旨在帮助企业利用AI能力、提示工程和ChatGPT的解决方案循环来改变企业景观。这本书提供了深入探讨ChatGPT的演变、能力以…

牛客NC362 字典序排列【中等 DFS Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/de49cf70277048518314fbdcaba9b42c 解题方法 DFS&#xff0c;剪枝Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回…

深入了解 CSS 预处理器 Sass

今天我们来深入探讨一下 CSS 预处理器 Sass。我们将学习什么是 Sass,如何使用它,以及它是如何工作的。 什么是 Sass? Sass 是 syntactically awesome style sheets 的缩写,是一种 CSS 预处理器。它是 CSS 的扩展,为基础 CSS 增加了更多的功能和优雅。普通的 CSS 代码很容…

BUG: VS Code C++输出中文乱码

BUG: VS Code C输出中文乱码 环境 Windows 11 VS Code 编辑器详情 在Windows 使用 cout 函数输出中文时出现乱码 问题的原因在cmd的显示编码和c程序编码的不同。cmd默认的是gbk编码&#xff0c;而VS Code 软件的CMD终端默认是utf-8编码&#xff0c;因而在输出中文文本时会出…

蓝桥杯嵌入式国赛笔记(4):多路AD采集

1、前言 蓝桥杯的国赛会遇到多路AD采集的情况&#xff0c;这时候之前的单路采集的方式就不可用了&#xff0c;下面介绍两种多路采集的方式。 以第13届国赛为例 2、方法一&#xff08;配置通道&#xff09; 2.1 使用CubeMx配置 设置IN13与IN17为Single-ended 在Parameter S…

XDebug配置几件教程,phpstorm实现http请求断点调试

写这篇的文章的初衷:网络上配置XDebug的文章有很多,XDebug也有官方的文档, PhpStorm也有官方的文档,为什么还要写那? 相信不少人,都有一种感觉,虽然教程很多,但是按教程走一遍,自己的确不能正常调试。 问题出在下面几个方面: 1. 对调试过程中,没有一定的认识,因此…

网络、HTTP、HTTPS、Session、Cookie、UDP、TCP

OSI 七层模型 应用层、表示层、会话层、传输层、网络层、数据链路层、物理层 TCP/IP 五层模型 应用层&#xff1a;为用户的应用进程提供网络通信服务&#xff08;协议&#xff1a;域名系统DNS协议&#xff0c;HTTP协议&#xff0c;SMTP协议&#xff09;传输层&#xff1a;负…

骨折检测数据集VOC+YOLO格式717张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;717 标注数量(xml文件个数)&#xff1a;717 标注数量(txt文件个数)&#xff1a;717 标注类别…

前端面试:项目细节重难点问题分享

面试官提问&#xff1a;我现在给你出一个项目实际遇到的问题&#xff1a;由于后端比较忙&#xff0c;所以我们这边的列表数据排序需要前端最近实现&#xff0c;那你会怎么实现排序呢&#xff1f; 答&#xff1a;我的回答&#xff1a;确实&#xff0c;数据都是由后端实现的&…

Jenkins的Pipeline流水线

目录 前言 流水线概念 什么是流水线 Jenkins流水线 pipeline node stage step 创建一个简单的流水线 创建Pipeline项目 选择模板 测试 前言 提到 CI 工具&#xff0c;首先想到的就是“CI 界”的大佬——Jenkjns,虽然在云原生爆发的年代,蹦出来了很多云原生的 CI 工具…

最简单的方式解决android studio 模拟器无法联网的问题

最简单的方式解决android studio 模拟器无法联网的问题 看了网上很多解决android studio内置模拟器无法联网的问题&#xff0c;基本上都是在模拟器手机上配置dns&#xff0c;个人试了多种办法也连不上网&#xff0c;现在给出一种&#xff0c;仅需要在命令行操作的解决安卓模拟…

【WEB前端2024】开源智体世界:乔布斯3D纪念馆-第28课-avatar玩家3D形象

【WEB前端2024】开源智体世界&#xff1a;乔布斯3D纪念馆-第28课-avatar玩家3D形象 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界…

电解式模具清洗机清洗模具的特点

电解式模具清洗机的特点可以归纳如下&#xff1a; 清洗效果显著&#xff1a; 电解式模具清洗机能够对模具进行深度清洁&#xff0c;有效去除模具表面的污垢、油污、除锈、硫化物、塑胶积碳等&#xff0c;使模具恢复原有的光洁度。清洗前后对比明显&#xff0c;模具更加光亮&am…

汇编:循环结构

16位汇编语言中的循环结构主要通过条件跳转指令&#xff08;如LOOP、JMP, JE, JNE, JG, JL, 等&#xff09;来实现&#xff0c;常见的循环类型包括for循环和while循环&#xff1b; Loop指令 LOOP指令的操作非常简单&#xff1a;它将CX寄存器的值减1&#xff0c;如果结果不为零…

VLDB ’25 最后 6 天截稿,58 个顶会信息纵览;ISPRS 城市分割数据集上线

「顶会」板块上线 hyper.ai 官网啦&#xff01;该板块为大家提供最新最全的 CCF A 类计算机顶会信息&#xff0c;包含会议简介、截稿倒计时、投稿链接等。 你是不是已经注册了顶会&#xff0c;但对截稿时间较为模糊&#xff0c;老是在临近 ddl 时才匆忙提交&#xff1b;又或者…

【面试八股总结】索引(二):B+树数据结构、索引使用场景、索引优化、索引失效

参考资料&#xff1a;小林coding、阿秀 一、为什么InnoDB采用B树作为索引数据结构&#xff1f; B 树是一个自平衡多路搜索树&#xff0c;每一个节点最多可以包括 M 个子节点&#xff0c;M 称为 B 树的阶&#xff0c;所以 B 树就是一个多叉树。 B 树与 B 树的差异&#xff1a;…