⭐算法OJ⭐并查集的应用/DFS/BFS:岛屿数量问题 Number of Islands

有一道很类似的题目:⭐算法OJ⭐并查集的应用/DFS/BFS:省份数量问题 Number of Provinces

今天这道题目DFS是最直接、最简单的解法,感兴趣的朋友可以尝试使用并查集解决。
在这里插入图片描述
说起群岛,不得不提起在北大西洋的腹地的法罗群岛。它们像是众神宴席上散落的碎屑,被遗忘在挪威与冰岛之间的汹涌波涛中,被风雕刻、被雾豢养。18座火山岛,340座山峰,1117公里犬牙交错的海岸线,以及比人类多1.5倍的绵羊——这里的每一寸土地都在低语:“时间在此失效。” 或许正如007电影在此取景时的台词:“人的一生应该去生活,而不仅仅是活着。” 法罗群岛,这片被《国家地理》称为“世界最美岛屿”的秘境,用狂风、绵羊和不可预测的天气,教会我们:真正的隐居,不是逃离世界,而是让世界自己找上门来——带着海鹦的鱼腥味、草皮屋顶的苔藓香,和永远湿漉漉的、倔强的诗意。

在这里插入图片描述

200. Number of Islands

Given an m x n 2D binary grid grid which represents a map of '1’s (land) and '0’s (water), return the number of islands.

An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

Example 1:

Input: grid = [
  ["1","1","1","1","0"],
  ["1","1","0","1","0"],
  ["1","1","0","0","0"],
  ["0","0","0","0","0"]
]
Output: 1

Example 2:

Input: grid = [
  ["1","1","0","0","0"],
  ["1","1","0","0","0"],
  ["0","0","1","0","0"],
  ["0","0","0","1","1"]
]
Output: 3

问题描述

给定一个由 ‘1’(陆地)和 ‘0’(水)组成的二维网格,计算岛屿的数量。岛屿被水包围,并且通过水平或垂直方向上相邻的陆地连接形成。

深度优先搜索 (DFS) 解法

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        if (grid.empty() || grid[0].empty()) return 0;
        
        int count = 0;
        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] == '1') {
                    dfs(grid, i, j);
                    ++count;
                }
            }
        }
        
        return count;
    }
    
private:
    void dfs(vector<vector<char>>& grid, int i, int j) {
        if (i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size() || grid[i][j] != '1') {
            return;
        }
        
        grid[i][j] = '0'; // 标记为已访问
        
        // 四个方向搜索
        dfs(grid, i - 1, j); // 上
        dfs(grid, i + 1, j); // 下
        dfs(grid, i, j - 1); // 左
        dfs(grid, i, j + 1); // 右
    }
};

广度优先搜索 (BFS) 解法

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        if (grid.empty() || grid[0].empty()) return 0;
        
        int count = 0;
        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] == '1') {
                    bfs(grid, i, j);
                    ++count;
                }
            }
        }
        
        return count;
    }
    
private:
    void bfs(vector<vector<char>>& grid, int i, int j) {
        queue<pair<int, int>> q;
        q.push({i, j});
        grid[i][j] = '0'; // 标记为已访问
        
        int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        
        while (!q.empty()) {
            auto curr = q.front();
            q.pop();
            
            for (auto dir : dirs) {
                int x = curr.first + dir[0];
                int y = curr.second + dir[1];
                
                if (x >= 0 && x < grid.size() && y >= 0 && y < grid[0].size() && grid[x][y] == '1') {
                    grid[x][y] = '0';
                    q.push({x, y});
                }
            }
        }
    }
};

并查集 (Union-Find) 解法

class UnionFind {
public:
    UnionFind(vector<vector<char>>& grid) {
        count = 0;
        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] == '1') {
                    parent.push_back(i * n + j);
                    ++count;
                } else {
                    parent.push_back(-1);
                }
                rank.push_back(0);
            }
        }
    }
    
    int find(int i) {
        if (parent[i] != i) {
            parent[i] = find(parent[i]);
        }
        return parent[i];
    }
    
    void unite(int x, int y) {
        int rootx = find(x);
        int rooty = find(y);
        if (rootx != rooty) {
            if (rank[rootx] < rank[rooty]) {
                swap(rootx, rooty);
            }
            parent[rooty] = rootx;
            if (rank[rootx] == rank[rooty]) {
                rank[rootx] += 1;
            }
            --count;
        }
    }
    
    int getCount() const {
        return count;
    }

private:
    vector<int> parent;
    vector<int> rank;
    int count;
};

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        if (grid.empty() || grid[0].empty()) return 0;
        
        int m = grid.size();
        int n = grid[0].size();
        UnionFind uf(grid);
        
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == '1') {
                    grid[i][j] = '0';
                    if (i - 1 >= 0 && grid[i-1][j] == '1') {
                        uf.unite(i * n + j, (i-1) * n + j);
                    }
                    if (i + 1 < m && grid[i+1][j] == '1') {
                        uf.unite(i * n + j, (i+1) * n + j);
                    }
                    if (j - 1 >= 0 && grid[i][j-1] == '1') {
                        uf.unite(i * n + j, i * n + j - 1);
                    }
                    if (j + 1 < n && grid[i][j+1] == '1') {
                        uf.unite(i * n + j, i * n + j + 1);
                    }
                }
            }
        }
        
        return uf.getCount();
    }
};

复杂度分析

DFS/BFS解法:

  • 时间复杂度: O(M×N),其中 M 是行数,N 是列数
  • 空间复杂度: O(M×N) 最坏情况下(全为陆地时递归深度)

并查集解法:

  • 时间复杂度: O(M×N×α(M×N)),其中 α 是反阿克曼函数
  • 空间复杂度: O(M×N) 用于存储父数组和秩数组

DFS和BFS解法通常更直观,而并查集解法在处理动态连接问题时更有优势。根据具体问题需求选择合适的解法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值