【DFS&并查集】岛屿数量

文章介绍了如何利用深度优先搜索(DFS)和并查集数据结构解决寻找和合并岛屿的问题。在给定的二维字符网格中,1表示陆地,0表示水。DFS遍历未访问的陆地,并用并查集进行集合合并,最后返回并查集的集合数量作为岛屿的总数。
摘要由CSDN通过智能技术生成

在这里插入图片描述
经典的dfs/bfs问题,给一个起点开始搜索,满足条件则继续调用dfs/bfs

从没有访问过的某个陆地出发,将所有能到达的陆地的状态都记录为已访问。下次出发不从已访问的陆地出发,每次出发前都把岛屿数 + 1即可

class Solution {
public:
    vector<vector<bool>> is_visited;
    const vector<pair<int, int>> direction = {{1, 0}, {0, -1}, {-1, 0}, {0, 1}};
    int m_;
    int n_;

    bool is_valid(int x, int y){
        return x >= 0 && x < m_ && y >= 0 && y < n_;
    }

    void dfs(const vector<vector<char>>& grid, int i, int j) {
        is_visited[i][j] = true;
        for (auto d : direction) {
            int x = i + d.first;
            int y = j + d.second;
            if (is_valid(x, y) && !is_visited[x][y] && grid[x][y] == '1') {
                dfs(grid, x, y);
            }
        }
    }

    int numIslands(vector<vector<char>>& grid) {
        m_ = grid.size();
        n_ = grid[0].size();
        is_visited.resize(m_, vector<bool>(n_, false));
        int ans = 0;
        for(int i = 0; i < m_; i++){
            for(int j = 0; j < n_; j++){
                if(!is_visited[i][j] && grid[i][j] == '1'){
                    dfs(grid, i, j);
                    ans++;
                }
            }
        }
        return ans;
    }
};

遍历二维数组,合并不同的坐标时,在每个陆地坐标处查看自己右侧和下方的位置是否是陆地,如果是,合并当前陆地和自己右侧或下方的陆地

遍历完成后,并查集构造完成,直接获取并查集的集合数即可

class UnionFind{
    public:
        UnionFind(const vector<vector<char>>& grid){
            m_ = grid.size();
            n_ = grid[0].size();
            for(int i = 0; i < m_; i++){
                for(int j = 0; j < n_; j++){
                    if(grid[i][j] == '1') parent[i * n_ + j] = i * n_ + j;
                }
            }
        }

        int find_root(int x){
            // x不存在于并查集
            if(parent.find(x) == parent.end()) return -1;
            if(x == parent[x]) return x;
            parent[x] = find_root(parent[x]);
            return parent[x];
        }

        void merge(int x, int y){
            x = find_root(x);
            y = find_root(y);
            if(x != y) parent[x] = y;
        }

        int get_find_num() {
            unordered_set<int> st;
            // 遍历并查集,得到集合数量
            for (auto iter = parent.begin(); iter != parent.end(); iter++) {
                st.insert(find_root((*iter).first));
            }
            return st.size();
        }

    private:
        unordered_map<int, int> parent;  // 并查集
        int m_;
        int n_;
};

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        UnionFind uf(grid);
        int m = grid.size();
        int n = grid[0].size();
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                // 如果自己右边或者下面是陆地,则合并集合
                if(grid[i][j] == '0') continue;
                if(i < m - 1){
                    // 可以查看下方
                    if(grid[i + 1][j] == '1') uf.merge(i * n + j, (i + 1) * n + j);
                }
                if(j < n - 1){
                    // 可以查看右边
                    if(grid[i][j + 1] == '1') uf.merge(i * n + j, i * n + (j + 1));
                }
            }
        }
        return uf.get_find_num();
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

bugcoder-9905

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

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

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

打赏作者

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

抵扣说明:

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

余额充值