FloodFill算法——搜索算法

一、什么是FloodFill算法

FloodFill算法字面意思就是洪水灌溉法,比如我们有这么一块地:

0表示平原,正数表示高地,负数表示凹地,那么当洪水来临时这些凹地会被优先灌满。而我们要找的正是这些联通块,如:

它是一种暴力搜索的思想,只要我们把每个地方都搜索一遍,那么最终的结果必定会水落石出。 通常可以使用BFS、DFS或并查集解决。

BFS(广度优先搜索)------搜索算法_广度优先搜索bfs-CSDN博客

DFS+回溯+剪枝(深度优先搜索)------搜索算法-CSDN博客

接下来我们直接从题中感受。

二、试题一:岛屿数量

我们可以使用两层for循环找到没有搜索过的"1"然后在从这个"1"开始进行BFS或DFS展开,在期间使用哈希表记录每个"1"是否已经搜索过。每一次新的展开之前做一下计数,最后得到最终答案。

BFS代码示例:

cpp 复制代码
class Solution {
public:
    int n=0,m=0,ret=0;
    int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
    int numIslands(vector<vector<char>>& grid)
    {
        n=grid.size(),m=grid[0].size(); 
        vector<vector<bool>> hash(n,vector<bool>(m));
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                if(grid[i][j]=='1'&&!hash[i][j]) bfs(i,j,grid,hash);  
        return ret;
    }
    void bfs(int i,int j,vector<vector<char>>& grid,vector<vector<bool>>& hash)
    {
        ret++;
        queue<pair<int,int>> q;
        hash[i][j]=true;
        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<n&&y>=0&&y<m&&grid[x][y]=='1'&&!hash[x][y])
                {
                    q.push({x,y});
                    hash[x][y]=true;
                }
            }
        }
    }
};

DFS代码示例:

cpp 复制代码
class Solution {
public:
    int n=0,m=0,ret=0;
    int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
    int numIslands(vector<vector<char>>& grid)
    {
        n=grid.size(),m=grid[0].size();
        vector<vector<bool>> hash(n,vector<bool>(m));
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                if(grid[i][j]=='1'&&!hash[i][j])
                {
                    ret++;
                    dfs(i,j,grid,hash);
                }
        return ret;
    }
    void dfs(int i,int j,vector<vector<char>>& grid,vector<vector<bool>>& hash)
    {
        hash[i][j]=true;
        for(int k=0;k<4;k++)
        {
            int x=i+dx[k],y=j+dy[k];
            if(x>=0&&x<n&&y>=0&&y<m&&grid[x][y]=='1'&&!hash[x][y])
                dfs(x,y,grid,hash);
        }
    }
};

三、试题二:太平洋大西洋水流问题

按题意,如果一个数能够与上边界和左边界元素联通,那么它就能流入"太平洋",如果与右边界或下边界元素联通则流入"大西洋" 。

如果我们一个元素一个元素的去搜索,去看它流入"太平洋",还是"大西洋",那么效率势必会很低。我们可以直接从边界扩展,能被上边界和左边界扩展到的是"太平洋",能被下边界和右边界扩展到的是"大西洋"。所以需要使用一个哈希表记录两个状态("大西洋,"太平洋"),可以使用一个pair<bool,bool>作为哈希表的元素类型。

DFS代码示例:

cpp 复制代码
class Solution {
public:
    vector<vector<pair<bool,bool>>> hash;
    int n=0,m=0;
    vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights)
    {
        n=heights.size(),m=heights[0].size();
        hash.resize(n);
        for(int i=0;i<n;i++) hash[i].resize(m,{false,false});
        for(int j=0;j<m;j++) dfs(0,j,heights,1),dfs(n-1,j,heights,2);
        for(int i=0;i<n;i++) dfs(i,0,heights,1),dfs(i,m-1,heights,2);
        vector<vector<int>> ret;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                if(hash[i][j].first&&hash[i][j].second) ret.push_back({i,j});
        return ret;
    }
    int dx[4]={0,0,1,-1},dy[4]={-1,1,0,0};
    void dfs(int i,int j,vector<vector<int>>& heights,int f)
    {
        f==1?hash[i][j].first=true:hash[i][j].second=true;
        for(int k=0;k<4;k++)
        {
            int x=dx[k]+i,y=dy[k]+j;
            if(x>=0&&x<n&&y>=0&&y<m&&heights[i][j]<=heights[x][y])
            {
                if(f==1&&hash[x][y].first) continue;
                if(f==2&&hash[x][y].second) continue;
                dfs(x,y,heights,f);
            }
        }
    }
};

BFS代码示例:

cpp 复制代码
class Solution {
public:
    vector<vector<pair<bool,bool>>> hash;
    int n=0,m=0;
    vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights)
    {
        n=heights.size(),m=heights[0].size();
        hash.resize(n);
        for(int i=0;i<n;i++) hash[i].resize(m,{false,false});

        for(int j=0;j<m;j++) bfs(0,j,heights,1),bfs(n-1,j,heights,2);
        for(int i=0;i<n;i++) bfs(i,0,heights,1),bfs(i,m-1,heights,2);
        vector<vector<int>> ret;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                if(hash[i][j].first&&hash[i][j].second) ret.push_back({i,j});
        return ret;
    }
    int dx[4]={0,0,1,-1},dy[4]={-1,1,0,0};
    void bfs(int i,int j,vector<vector<int>>& heights,int f)
    {
        f==1?hash[i][j].first=true:hash[i][j].second=true;
        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<n&&y>=0&&y<m&&heights[a][b]<=heights[x][y])
                {
                    if(f==1&&hash[x][y].first) continue;
                    if(f==2&&hash[x][y].second) continue;
                    f==1?hash[x][y].first=true:hash[x][y].second=true;
                    q.push({x,y});
                }
            }
        }
    }
};
相关推荐
其实防守也摸鱼12 分钟前
信创安全竞赛知识总结与题库
大数据·网络·人工智能·算法·安全·php
旖旎夜光41 分钟前
【C++ 基础入门】类和对象(上):封装、对象模型与 this 指针
开发语言·c++·笔记·学习
小超人诞生日记1 小时前
C++ 智能指针的使用及其原理详解
c++·算法
akinggw2 小时前
libagentcore - 一个基于c++的AI多agent系统升级到2.0版本
开发语言·jvm·c++
繁星蓝雨3 小时前
C++设计原理———多重继承(虚基类、菱形继承、委托、重命名、基类和成员初始化)
c++·委托·多重继承·mi·显式初始化列·虚基类·对象布局
旖旎夜光4 小时前
【C++ 基础入门】命名空间、输入输出、缺省参数与函数重载
开发语言·c++·笔记·学习
扶尔魔ocy5 小时前
【QT入门到晋级】用开源的自定义控件开发
c++·qt·自定义控件
AiNightVision5 小时前
无人机夜视模块如何选择?——从参数指标到系统集成的完整选型指南
人工智能·算法·计算机视觉·车载系统·无人机·视频·智能硬件
牧羊人.3336 小时前
卷积神经网络之VGG
人工智能·深度学习·神经网络·算法·cnn