岛屿数量(DFS / BFS/并查集)

最近学习了深度优先搜索算法(DFS),特针对该算法找了题目来做,该题就是典型的运用了搜索算法的题目

现在先讲一下使用DFS怎么做这道题(BFS暂时未掌握,后续会补上~~)

思路上也比较容易想到

首先我们肯定要先创建二维数组,并且填入一定的数据,之后我们就可以开始遍历该数组了,我们一旦遇到“ 1 ”,我们先把这个“ 1 ”变成“ 0 ”后我们就开始搜索这个1附近的“上下左右”,如果还有“ 1 ”,我们还把它变成“0”之后搜索这个“ 1 ”的“上下左右”,直到附近全为“0”为止

对了还记得我们DFS的模板吗!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

DFS(深度优先搜索算法)入门_ZZZWWWFFF_的博客-CSDN博客

上面的模板是我在这篇博客里面提到过的,感兴趣的同学可以看看

下面就是代码实现啦

因为交题时采用的是“核心代码”模式,所以没有写出“完整”代码

        下面有两种DFS的写法(实际上差别不大)

class Solution {
public:

int nextt[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int n,m,tx,ty,count=0;
 
    int solve(vector<vector<char> >& grid) {
        n=grid.size();//计算行数
        m=grid[0].size();//计算列数
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(grid[i][j]=='1')
                {
                    count++;
                    dfs(i,j,grid);
                }
            }
        }
        return count;
    }
    void dfs(int x,int y,vector<vector<char> >& grid)
{
    if(grid[x][y]=='1')
    {
        grid[x][y]='0';
        for(int i=0;i<=3;i++)
        {
            tx=x+nextt[i][0];
            ty=y+nextt[i][1];
            if(tx < 0 || ty < 0 || tx >= grid.size() || ty >= grid[0].size()){
                continue;
            }
            if(grid[tx][ty]=='1')
            dfs(tx,ty,grid);
        }
    }
}
};
class Solution {
public:

int nextt[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int n,m,tx,ty,count=0;

    int solve(vector<vector<char> >& grid) {
        n=grid.size();//计算行数
        m=grid[0].size();//计算列数
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(dfs(i,j,grid))
                {
                    count++;
                    
                }
            }
        }
        return count;
    }
    int dfs(int x,int y,vector<vector<char> >& grid)
{
    if(grid[x][y]=='1')
    {
        grid[x][y]='0';
        for(int i=0;i<=3;i++)
        {
            tx=x+nextt[i][0];
            ty=y+nextt[i][1];
            if(tx < 0 || ty < 0 || tx >= grid.size() || ty >= grid[0].size()){
                continue;
            }
            if(grid[tx][ty]=='1')
            dfs(tx,ty,grid);
        }
        return 1;
    }
        return 0;
}
};

        下面给出用BFS写的代码

为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为 1,则将其加入队列(注意哦,是将其对应的下标存放到队列中的)开始进行广度优先搜索。在广度优先搜索的过程中,每个搜索到的 1 都会被重新标记为 0     直到队列为空,搜索结束。

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        int nr = grid.size();//行数
        if (!nr) return 0;//判断边界情况
        int nc = grid[0].size();//列数
 
        int num_islands = 0;//用于计数
        //遍历二维网格
        for (int r = 0; r < nr; ++r) {
            for (int c = 0; c < nc; ++c) {
                //满足条件时进来,否则进入下一次循环
                if (grid[r][c] == '1') {
                    ++num_islands;
                    grid[r][c] = '0';
                    //定义一个队列,用于存放下标信息
                    //注意对pair的理解,可以看作是内部有两个元素的结构体
                    queue<pair<int, int>> neighbors;
                    neighbors.push({r, c});//将'1'的下标信息入队
                    while (!neighbors.empty()) {
                        pair<int,int> rc = neighbors.front();//访问队首元素
                        neighbors.pop();//队首元素出队
                        int row = rc.first;//队首元素所对应的行号
                        int col = rc.second;//队首元素所对应的列号
                        //将它上下左右的‘1’都同化成‘0’
                        //上
                        //row - 1 >= 0 判断位置是否合法
                        if (row - 1 >= 0 && grid[row-1][col] == '1') {
                            neighbors.push({row-1, col});
                            grid[row-1][col] = '0';
                        }
                        //下
                        //row + 1 < nr 判断位置是否合法
                        if (row + 1 < nr && grid[row+1][col] == '1') {
                            neighbors.push({row+1, col});
                            grid[row+1][col] = '0';
                        }
                        //左
                        //col - 1 >= 0 判断位置是否合法
                        if (col - 1 >= 0 && grid[row][col-1] == '1') {
                            neighbors.push({row, col-1});
                            grid[row][col-1] = '0';
                        }
                        //右
                        //col + 1 < nc 判断位置是否合法
                        if (col + 1 < nc && grid[row][col+1] == '1') {
                            neighbors.push({row, col+1});
                            grid[row][col+1] = '0';
                        }
                    }
                }
            }
        }
 
        return num_islands;
    }
};

以上代码较为冗长,若读者无法理解,这边建议自己调试一遍

     下面是并查集的写法

思路是我们遍历整个数组,如果一个‘1’周围有‘1’,就把它们并起来

class Solution {
public:
int n, m,ans=0, nextt[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };
void init(int father[])
{
    for (int i = 0; i < n * m; i++)//初始化自己为根
    {
        father[i] = i;
    }
}

int find(int x, int father[])//寻找根 同时压缩路径
{
    if (father[x] == x)
    {
        return x;
    }
    else
    {
        return father[x] = find(father[x], father);
    }
}

void join(int a, int b, int father[])
{
    int root1 = find(a, father);
    int root2 = find(b, father);
    if (root1 != root2)
    {
        father[root2] = root1;
        ans--;//注意并起来之后--(因为并起来之后就是一个岛屿)
    }
}
int numIslands(vector<vector<char>>& grid) {
    n = grid.size();
    m = grid[0].size();
    int* father = new int[n * m];
    init(father);//初始化
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (grid[i][j] == '1')
            {
                ans++;//计算岛屿数量(假设每一个都是岛屿)
                for (int z = 0; z < 4; z++)//将周围的'1'并起来
                {
                    int tx = i + nextt[z][0];
                    int ty = j + nextt[z][1];
                    if (tx < 0 || ty < 0 || tx >= n || ty >= m)//判断是否越界
                    {
                        continue;
                    }
                    if (grid[tx][ty] == '1')
                    {
                        join(i * m + j, tx * m + ty, father);///并起来
                    }
                }
            }
        }
    }
    delete[]father;//记得delete
    return ans;
}
};

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZZZWWWFFF_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值