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';}}}//处理边界的Ovoid 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';}}}//处理边界的Ovoid 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);}}
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【架构-16】安全架构设计理论

信息安全面临的威胁 主动攻击&#xff1a;可能改变信息或危害系统的攻击就是主动攻击 被动攻击&#xff1a;攻击者的目的只是获取信息&#xff0c;不会改变信息或危害系统。&#xff08;网络监听、信息截取、流量分析&#xff09; 信息安全体系架构设计 信息安全体系架构。具…

Llama模型家族训练奖励模型Reward Model技术及代码实战(二)从用户反馈构建比较数据集

LlaMA 3 系列博客 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;一&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;二&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;三&#xff09; 基于 LlaMA…

【设计模式】JAVA Design Patterns——Circuit Breaker(断路器模式)

&#x1f50d;目的 以这样一种方式处理昂贵的远程服务调用&#xff0c;即单个服务/组件的故障不会导致整个应用程序宕机&#xff0c;我们可以尽快重新连接到服务 &#x1f50d;解释 真实世界例子 想象一个 Web 应用程序&#xff0c;它同时具有用于获取数据的本地文件/图像和远程…

Linux软硬链接详解

软链接&#xff1a; ln -s file1 file2//file1为目标文件&#xff0c;file2为软链接文件 演示&#xff1a; 从上图可以得出&#xff1a; 软链接本质不是同一个文件&#xff0c;因为inode不同。 作用&#xff1a; 软连接就像是Windows里的快捷方式&#xff0c;里面存放的是目标…

苹果手机数据不慎删除?这4个方法果粉必看!

苹果手机该怎么恢复丢失的数据呢&#xff1f;有时候会因为使用不当或者是被他人误删等原因&#xff0c;导致重要的数据丢失&#xff0c;这时我们需要找回丢失手机数据&#xff0c;小编给大家分享4种恢复苹果手机数据的技巧&#xff0c;大家赶紧来学一学吧&#xff01; 一、iclo…

SpringBoot 返回值 i18n 自动处理

定义基础通用类 首先定义一波错误码&#xff1a;ResultCode Getter AllArgsConstructor public enum ResultCode {SUCCESS(200, "请求成功", "request.success"),Fail(400, "请求失败", "request.failed"),PASSWORD_NOT_MATCH(1000…

Parasoft C++Test软件静态分析操作指南_编码规范/标准检查

系列文章目录 Parasoft CTest软件安装指南 Parasoft CTest软件静态分析操作指南_编码规范/标准检查 Parasoft CTest软件静态分析操作指南_软件质量度量 Parasoft CTest软件静态分析_自动提取静态分析数据生成文档 Parasoft CTest软件单元测试_操作指南 Parasoft CTest软件单元…

微信小程序多端应用Donut Android生成签名

一、生成签名的作用 确保应用的完整性&#xff1a;签名可以确保应用在发布后没有被修改。如果应用被修改&#xff0c;签名就会改变&#xff0c;Android系统就会拒绝安装。确定应用的唯一身份&#xff1a;签名是应用的唯一标识&#xff0c;Android系统通过签名来区分不同的应用…

设计模式18—— 迭代器模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用&#xff0c;主要是下面的UML图可以起到大作用&#xff0c;在你学习过一遍以后可能会遗忘&#xff0c;忘记了不要紧&#xff0c;只要看一眼UML图就能想起来了。同时也请大家多多指教。 迭代器模式&#xff08;Iterat…

基环树学习笔记

理论基础&#xff1a; 内向基环树就是每个联通块有且仅有一个环&#xff0c;并且出度为1的有向图&#xff0c;每一个内向基环树都是由联通环和指向联通环的树枝组成。而且基环可以只有两个节点构成。 Leetcode - 2127&#xff1a;参加会议的最多员工数 题目&#xff1a; 一个…

【RabbitMQ】SpringAMQP--消息转换器

SpringAMQP–消息转换器 测试发送Object类型消息 1.声明队列 Configuration public class FanoutConfig {Beanpublic Queue objectQueue(){return new Queue("object.queue");} }运行消费者后&#xff1a; 2.发送消息 RunWith(SpringRunner.class) SpringBootTes…

【数据结构与算法】七大排序算法(上)

【数据结构与算法】七大排序算法(上) &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;数据结构与算法&#x1f345; &#x1f33c;文章目录&#x1f33c; 1. 排序的概念及应用 1.1 排序的概念 1.2 排序的应用 1.3 常见排序算法 2. 常…

开源博客项目Blog .NET Core源码学习(23:App.Hosting项目结构分析-11)

本文学习并分析App.Hosting项目中后台管理页面的标签管理页面、轮播图维护页面。 标签管理页面 标签管理页面用于显示、检索、新建、编辑、删除标签数据&#xff0c;以便在前台页面的首页及文章专栏等页面显示标签数据。标签管理页面附带一新建及编辑页面&#xff0c;以支撑新…

如同“水生态”的存储引擎|OceanBase数据转储合并技术解读(一)

本系列文章主要围绕 OceanBase数据库存储引擎中的转储合并进行解读&#xff0c;涉及到数据存储、转储合并、数据校验等方面的内容&#xff0c;旨在让读者了解OceanBase数据库的存储引擎中与转储合并有关的各种概念&#xff0c;帮助读者更好地理解OceanBase数据库的存储技术原理…

基于STM32实现智能饮水机控制系统

目录 引言环境准备智能饮水机控制系统基础代码示例&#xff1a;实现智能饮水机控制系统 温度传感器数据读取水泵和加热器控制水位传感器数据读取用户界面与显示应用场景&#xff1a;家庭和办公室的智能饮水管理问题解决方案与优化收尾与总结 1. 引言 本教程将详细介绍如何在S…

关于pdfbox读取pdf

最近&#xff0c;想着将pdf的文件进行读取其内容&#xff0c;发现了一个比较好用的依赖pdfbox。目前使用这个依赖&#xff0c;进行实现一个简单实例&#xff0c;如果之后需要使用到更深的了解&#xff0c;会进行更新。这里提醒一下&#xff1a;jdk8尽量采用pdfbox3.x版本。 对…

Linux一键安装Docker、kkfileviewer

Linux一键安装Docker、kkfileviewer 一、安装docker 安装docker脚本 vi initDocker.sh脚本内容 #安装前先更新yum&#xff0c;防止连接镜像失败 yum -y update#卸载系统之前的docker&#xff08;可选择&#xff0c;我这里直接注释了&#xff09; #yum remove docker docker…

香橙派KunpengPro测评之使用C语言操控40pin引脚

香橙派KunpengPro测评之使用C语言操控40pin引脚 香橙派KunpengPro介绍香橙派实物图香橙派登录界面香橙派KunpengPro的登录界面香橙派KunpengPro的原始桌面香橙派KunpengPro内安装了VScode等软件香橙派KunpengPro的终端 香橙派硬件参数核心性能图形与显示接口丰富性扩展与兼容性…

十四天学会Vue——Vue核心(理论+实战)上篇(第一天)

一、Vue核心&#xff08;上篇&#xff09; 热身tops&#xff1a;选取开发模式 ①用于开发模式 我们只需要知道 我们是开发模式&#xff0c;开发模式他会跟你提示代码出现错误的地方以及出错原因&#xff0c;而生产模式比较简洁。 ②用于生产模式 1.1 new Vue()实例 了解Vue&a…

数据库语法树优化

目录 一、σ、π、⋈ 1.选择σ 2.投影π 3.连接⋈ 二、 构建语法树 ① 解读sql语句 ② 写出关系代数表达式 ③ 画出语法树 三、优化语法树 四、练习 语法树优化方法 一、σ、π、⋈ 1.选择σ 选择就是在关系R中选择满足给定条件的诸元组。 通过条件SdeptIS选择出系别…