FloodFill

"绝境之中才窥见,Winner,Winner" 


FloodFill算法简介:

        floodfill又翻译成漫水填充。我们可以将下面的矩阵理解为一片具有一定高度的坡地,此时突发洪水,洪水会将高度<0的地方填满。        

        话句话来说,FloodFill算法是为了找出那些具有相同性质的区域。那我们现在就来看看一些经典的使用floodfill算法的题目。


图像渲染

(1) 题目解析        

                这类题目的代码部分,都是将模拟的过程转化成代码。

(2) 算法代码

dfs:

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

    void dfs(vector<vector<int>>& image, int i,int j,int newcolor)
    {
        // 从这一点出发,每一个方向去 递归相邻节点
        image[i][j] = newcolor;
        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,newcolor);
            }
        }
    }
};

 bfs:       

class Solution {
public:
    typedef pair<int,int> PII;
    int m,n;
    int prev;
    int dx[4] = {0,0,1,-1};
    int dy[4] = {1,-1,0,0};
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {
        m = image.size(),n = image[0].size();
        if(image[sr][sc] == color) return image;
        // 当前位置会被修改为newcolor 这里是保存需要被渲染的值
        prev = image[sr][sc];
        bfs(image,sr,sc,color);
        return image;
    }

    void bfs(vector<vector<int>>& image, int i,int j,int newcolor)
    {
        queue<PII> que;
        image[i][j] = newcolor;
        que.push({i,j});
        while(que.size())
        {
            // 取出已经被渲染的位置,并将它的相邻位置,满足条件的 插入进队列
            auto [a,b] = que.front();
            que.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 && image[x][y] == prev)
                {
                    image[x][y] = newcolor;
                    que.push({x,y});
                }
            }
        }
    }
};

岛屿数量

(1) 题目解析        

注: 进行bfs或dfs时需要注意,防止统计已经遍历过的位置。我们有两种解决方法,其一就是对原数组内部的值进行修改,区别于目标条件,其二就是创建一个新的布尔数组,标记每一个遍历过的点。

(2) 算法代码

dfs:        

class Solution {
public:
    int m,n;
    bool vis[301][301];
    int dx[4] = {0,0,1,-1};
    int dy[4] = {1,-1,0,0};
    int numIslands(vector<vector<char>>& grid) {
        m = grid.size(),n = grid[0].size();
        int count = 0;
        for(int i=0;i<m;++i)
            for(int j=0;j<n;++j)
            {
                // 遍历到岛屿进行一次dfs 并且这个位置没有被访问过
                if(grid[i][j] == '1' && !vis[i][j]) 
                {
                    count++;
                    vis[i][j] = true; // 标记
                    dfs(grid,i,j);
                }
            }
        
        return count;
    }

    void dfs(vector<vector<char>>& grid,int i,int j)
    {
        // 这里的dfs 只需将与(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 && grid[x][y] == '1' && !vis[x][y])
            {
                vis[x][y] = true;
                dfs(grid,x,y);
            }
        }
    }
};

bfs:

    class Solution {
    public:
        int m,n;
        bool vis[301][301];
        int dx[4] = {0,0,1,-1};
        int dy[4] = {1,-1,0,0};
        int numIslands(vector<vector<char>>& grid) {
            m = grid.size(),n = grid[0].size();
            int count = 0;
            for(int i=0;i<m;++i)
                for(int j=0;j<n;++j)
                {
                    // 遍历到岛屿进行一次dfs 并且这个位置没有被访问过
                    if(grid[i][j] == '1' && !vis[i][j]) 
                    {
                        count++;
                        vis[i][j] = true; // 标记
                        bfs(grid,i,j);
                    }
                }
            
            return count;
        }

        void bfs(vector<vector<char>>& grid,int i,int j)
        {
            // 这里的bfs 只需将与(i,j) 相连的岛屿统计即可
            // bfs通常需要借助队列来实现
            queue<pair<int,int>> que;
            que.push({i,j});
            while(que.size())
            {
                auto [a,b] = que.front();
                que.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])
                    {
                        vis[x][y] = true;
                        que.push({x,y});
                    }
                }
            }
        }
    };

岛屿的最大面积

(1) 题目解析        

        这道题和上个题目十分类似,只不过这道题目的结果是求这些岛屿的最大面积,所以,我们需要对相连岛屿数量进行统计,并最终返回一个最大值。

(2) 算法代码

dfs:

class Solution {
public:
    int m,n;
    bool vis[301][301];
    int dx[4] = {0,0,1,-1};
    int dy[4] = {1,-1,0,0};
    int ret,count;
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        m = grid.size(),n = grid[0].size(),ret = 0;
        for(int i=0;i<m;++i)
            for(int j=0;j<n;++j)
            {
                // 遍历到岛屿进行一次dfs 并且这个位置没有被访问过
                if(grid[i][j] == 1 && !vis[i][j]) 
                {
                    count = 0;
                    dfs(grid,i,j);
                    ret = max(ret,count);
                }
            }
        return ret;
    }

    void dfs(vector<vector<int>>& grid,int i,int j)
    {
        vis[i][j] = true;
        count++;
        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);
            }
        }
    }
};

bfs:

class Solution {
public:
    int m,n;
    bool vis[301][301];
    int dx[4] = {0,0,1,-1};
    int dy[4] = {1,-1,0,0};
    int ret,count;
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        m = grid.size(),n = grid[0].size(),ret = 0;
        for(int i=0;i<m;++i)
            for(int j=0;j<n;++j)
            {
                // 遍历到岛屿进行一次dfs 并且这个位置没有被访问过
                if(grid[i][j] == 1 && !vis[i][j]) 
                {
                    count = 0;
                    vis[i][j] = true; // 标记
                    bfs(grid,i,j);
                    ret = max(ret,count);
                }
            }
        return ret;
    }

    void bfs(vector<vector<int>>& grid,int i,int j)
    {
        // 这里的bfs 只需将与(i,j) 相连的岛屿统计即可
        // bfs通常需要借助队列来实现
        queue<pair<int,int>> que;
        que.push({i,j});
        count++;
        while(que.size())
        {
            auto [a,b] = que.front();
            que.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])
                {
                    count++;
                    vis[x][y] = true;
                    que.push({x,y});
                }
            }
        }
    }
};


被围绕的区域

(1) 题目解析        

        但其实,我们发现这两个dfs本质是做同样的事情,但却因为判断边界,我们需要写两份不同的dfs,这是蛮麻烦的事情。我们换个思路,直接用一个dfs将边界的'O',进行过滤,并填上不相关的字符,再将整个数组遍历,遇到‘O’改为‘X’,遇到这个不相关的字符,改为'O'。

(2) 算法代码

dfs:

class Solution {
public:
    int m,n;
    bool vis[201][201];
    int dx[4] = {0,0,-1,1};
    int dy[4] = {1,-1,0,0};
    void solve(vector<vector<char>>& board) {
        m = board.size(),n = board[0].size();
        // 处理第一行和最后一行
        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);
        }

        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);
            }
        }
    }
};

bfs:        

class Solution {
public:
    int m,n;
    bool vis[201][201];
    int dx[4] = {0,0,-1,1};
    int dy[4] = {1,-1,0,0};
    void solve(vector<vector<char>>& board) {
        m = board.size(),n = board[0].size();
        // 处理第一行和最后一行
        for(int j=0;j<n;++j)
        {
            if(board[0][j] == 'O') bfs(board,0,j);
            if(board[m-1][j] == 'O') bfs(board,m-1,j);
        }

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

        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 bfs(vector<vector<char>>& board,int i,int j)
    {
        board[i][j] = '.';
        queue<pair<int,int>> que;
        que.push({i,j});
        while(que.size())
        {
            auto [a,b] = que.front();
            que.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')
                {
                    board[x][y] = '.';
                    que.push({x,y});
                }
            }
        }
    }
};

扫雷

(1) 题目解析        

        经典的扫雷游戏,至于玩法也就不过多解释。该题目考察的地方就在于,点击一个点之后,从这个 点开始进行对相邻领域的展开,我们可以采用dfs或bfs完成。

        当挖出的位置是一个雷,将这个位置标记成‘X’,游戏结束。当挖出的一个地方是空位置,你需要首先去相邻区域查找是否有雷,如果没有发现雷,则标记为'B',否则就需要将搜查到的雷的个数,标记在该位置处。

(2) 算法代码

dfs:

class Solution {
public:
    int m,n;
    bool vis[51][51];
    // 扫雷位置有八个位置需要被展开
    int dx[8] = {0,0,-1,1,-1,1,-1,1};
    int dy[8] = {1,-1,0,0,1,-1,-1,1};
    vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
        m = board.size(),n = board[0].size();
        int i = click[0],j = click[1];
        if(board[i][j] == 'M')
            board[i][j] = 'X';
        else
            dfs(board,i,j);
        return board;
    }

    void dfs(vector<vector<char>>& board,int i,int j)
    {
        int count = 0;
        // 统计雷的数量
        for(int k=0;k<8;++k)
        {
            int x=i+dx[k],y=j+dy[k];
            if(x>=0 && x<m && y>=0 && y<n && board[x][y] == 'M') count++;
        }

        if(count){
            board[i][j] = count + '0';
        }
        else{
            board[i][j] = 'B';
            for(int k=0;k<8;++k)
            {
                int x=i+dx[k],y=j+dy[k];
                if(x>=0 && x<m && y>=0 && y<n && board[x][y] == 'E') dfs(board,x,y);
            }
        }
    }
};

bfs:        

class Solution {
public:
    int m,n;
    bool vis[51][51];
    // 扫雷位置有八个位置需要被展开
    int dx[8] = {0,0,-1,1,-1,1,-1,1};
    int dy[8] = {1,-1,0,0,1,-1,-1,1};
    vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
        m = board.size(),n = board[0].size();
        int i = click[0],j = click[1];
        if(board[i][j] == 'M')
            board[i][j] = 'X';
        else
            bfs(board,i,j);
        return board;
    }

    void bfs(vector<vector<char>>& board,int i,int j)
    {
        queue<pair<int,int>> que;
        que.push({i,j});
        vis[i][j] = true;

        while(que.size())
        {
            auto [a,b] = que.front();
            que.pop();
            
            int count = 0;
            // 统计雷的数量
            for(int k=0;k<8;++k)
            {
                int x=a+dx[k],y=b+dy[k];
                if(x>=0 && x<m && y>=0 && y<n && board[x][y] == 'M') count++;
            }

            if(count){
                board[a][b] = count + '0';
            }
            else{
                board[a][b] = 'B';
                for(int k=0;k<8;++k)
                {
                    int x=a+dx[k],y=b+dy[k];
                    if(x>=0 && x<m && y>=0 && y<n && board[x][y] == 'E')
                    {
                        // 这里改为'B' 避免被其他点统计到 队列中去
                        // 也可以使用 vis[x][y] = ture; 进行标记 不被统计 !!!
                        board[x][y] = 'B'; 
                        que.push({x,y});
                    }
                }
            }
        }
    }
};


本篇到此结束,感谢你的阅读。

祝你好运,向阳而生~

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

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

相关文章

uniapp+vue基于Android的校园二手跳蚤市场的设计与实现 微信小程序

实现功能&#xff1a; 用户管理&#xff1a;登陆、注册、注销、修改密码、上传头像、修改资料 发布与检索&#xff1a;发布商品、模糊搜索、人气排序、价格排序、时间排序、推送商品&#xff08;协同过滤算法实现个性化推荐&#xff09;&#xff0c;最新发布、分类检索 核心交易…

解密Kafka主题的分区策略:提升实时数据处理的关键

目录 一、Kafka主题的分区策略概述1.1 什么是Kafka主题的分区策略&#xff1f;1.2 为什么分区策略重要&#xff1f; 二、Kafka默认分区策略2.1 Round-Robin分区策略 三、自定义分区策略3.1 编写自定义分区器3.2 最佳实践&#xff1a;如何选择分区策略 四、分区策略的性能考量4.…

【数据中台】开源项目(2)-Dbus数据总线

1 背景 企业中大量业务数据保存在各个业务系统数据库中&#xff0c;过去通常的同步数据的方法有很多种&#xff0c;比如&#xff1a; 各个数据使用方在业务低峰期各种抽取所需数据&#xff08;缺点是存在重复抽取而且数据不一致&#xff09; 由统一的数仓平台通过sqoop到各个…

error LNK2038: 检测到“RuntimeLibrary”的不匹配项 解决方法

问题&#xff1a; 我们在使用Visual Studio编程的时候偶尔会遇到以下三种报错&#xff1a; error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MD_DynamicRelease”不匹配值“MDd_DynamicDebug” &#xff08;引用的是release模式&#xff0c;但设置成debug模式了…

【研究中2】sql server权限用户设置

--更新时间2023.11.26 21&#xff1a;30 负责人&#xff1a;jerrysuse DBAliCMSIF EXISTS (select * from sysobjects where namehkcms_admin)--判断是否存在此表DROP TABLE hkcms_adminCREATE TABLE hkcms_admin (id int identity(1, 1),--id int primary key identity…

本地运行“李开复”的零一万物 34B 大模型

这篇文章&#xff0c;我们来聊聊如何本地运行最近争议颇多的&#xff0c;李开复带队的国产大模型&#xff1a;零一万物 34B。 写在前面 零一万物的模型争议有很多&#xff0c;不论是在海外的社交媒体平台&#xff0c;还是在国内的知乎和一种科技媒体上&#xff0c;不论是针对…

【Spring】Spring事务失效问题

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…

058-第三代软件开发-文件Model

第三代软件开发-文件Model 文章目录 第三代软件开发-文件Model项目介绍文件Model 关键字&#xff1a; Qt、 Qml、 关键字3、 关键字4、 关键字5 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项目结合了 QML&#xff08;Qt Meta-Object Language&#xff09;…

智能头盔天眼摄像头、单兵执法记录仪等配合MESH自组网在应急指挥调度中的应用

智能头盔、天眼摄像头、头盔记录仪、头盔摄像头、单兵执法记录仪等配合MESH自组网在应急指挥调度中的应用。 20人背负单兵自组网&#xff08;带手咪&#xff09;到训练场&#xff0c;戴头盔&#xff0c;头盔上放头盔式摄像头&#xff0c;大功率自组网设置在制高点&#xff0c;…

【办公软件】电脑开机密码忘记了如何重置?

这个案例是家人的电脑&#xff0c;已经使用多年&#xff0c;又是有小孩操作过的&#xff0c;所以电脑密码根本不记得是什么了&#xff1f;那难道这台电脑就废了吗&#xff1f;需要重新装机吗&#xff1f;那里面的资料不是没有了&#xff1f; 为了解决以上问题&#xff0c;一般…

数据结构——哈夫曼树结构总结

一直在找工作&#xff0c;没时间写博客&#xff0c;现在找到工作了&#xff0c;博客回归~ 哈夫曼树定义及构建教程

C#,《小白学程序》第三课:类class,类的数组及类数组的排序

类class把数值与功能巧妙的进行了结合&#xff0c;是编程技术的主要进步。 下面的程序你可以确立 分数 与 姓名 之间关系&#xff0c;并排序。 1 文本格式 /// <summary> /// 同学信息类 /// </summary> public class Classmate { /// <summary> /…

IDM(Internet Download Manager)PC版提升下载速度与效率的利器

你是否曾经因为下载速度慢而感到烦恼&#xff1f;或者在下载大型文件时&#xff0c;经历了长时间的等待&#xff1f;如果你有这样的困扰&#xff0c;那么IDM&#xff08;Internet Download Manager&#xff09;就是你的救星&#xff01; IDM是一款高效、实用的下载管理器&…

Day42力扣打卡

打卡记录 统计子串中的唯一字符&#xff08;找规律&#xff09; 链接 大佬的题解 class Solution:def uniqueLetterString(self, s: str) -> int:ans total 0last0, last1 {}, {}for i, c in enumerate(s):total i - 2 * last0.get(c, -1) last1.get(c, -1)ans tot…

如何深刻理解从二项式分布到泊松分布

泊松镇贴 二项分布和泊松分布的表达式 二项分布&#xff1a; P ( x k ) C n k p k ( 1 − p ) n − k P(xk) C_n^kp^k(1-p)^{n-k} P(xk)Cnk​pk(1−p)n−k 泊松分布&#xff1a; P ( x k ) λ k k ! e − λ P(xk) \frac{\lambda^k}{k!}e^{-\lambda} P(xk)k!λk​e−…

NX二次开发UF_CURVE_ask_trim 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_trim Defined in: uf_curve.h int UF_CURVE_ask_trim(tag_t trim_feature, UF_CURVE_trim_p_t trim_info ) overview 概述 Retrieve the current parameters of an a…

车载通信架构 —— 传统车内通信网络CAN(可靠性为王)

车载通信架构 —— 传统车内通信网络CAN(可靠性为王) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非…

自建CA实战之 《0x03 代码签名》

自建CA实战之 《0x03 代码签名》 本文针对Windows平台&#xff0c;介绍如何使用自建CA来签发代码签名证书。 之前的文章中&#xff0c;我们介绍了如何自建CA&#xff0c;以及如何使用自建CA来签发Web服务器证书、客户端证书。 本文将介绍如何使用自建CA来签发代码签名证书。…

二叉树算法—后继节点

与其明天开始&#xff0c;不如现在行动&#xff01; 文章目录 1 后继节点1.1 解题思路1.2 代码实现 &#x1f48e;总结 1 后继节点 1.1 解题思路 二叉树节点结构定义如下&#xff1a; public static class Node { public int cal; public Node left; public Node right; public…

【C++初阶】STL之学习string的用法

目录 前言&#xff1a;一、认识下string1.1 什么是string1.2 为什么要有string 二、string 类的接口使用2.1 初始化与析构2.1.1 初始化2.1.2 析构 2.2 容量操作2.2.1 长度大小——size和length2.2.2 空间总大小——capacity2.2.3 判空——empty2.2.4 清空——clear2.2.5 预留空…