leetcode:200. 岛屿数量

题目来源

题目描述

在这里插入图片描述

在这里插入图片描述

题目解析

深度优先遍历DFS

目标是找到矩阵中 “岛屿的数量” ,上下左右相连的 1 都被认为是连续岛屿。

dfs方法: 设目前指针指向一个岛屿中的某一点 (i, j),寻找包括此点的岛屿边界。

  • 从 (i, j) 向此点的上下左右 (i+1,j),(i-1,j),(i,j+1),(i,j-1) 做深度搜索。
  • 终止条件:
    • (i, j) 越过矩阵边界;
    • grid[i][j] == 0,代表此分支已越过岛屿边界。
  • 搜索岛屿的同时,执行 grid[i][j] = ‘0’,即将岛屿所有节点删除,以免之后重复搜索相同岛屿。
  • 主循环:
    • 遍历整个矩阵,当遇到 grid[i][j] == ‘1’ 时,从此点开始做深度优先搜索 dfs,岛屿数 count + 1 且在深度优先搜索中删除此岛屿。
  • 复杂度:所有的数遍历一遍,所以复杂度是O(N*M)
class Solution {
    void infect(vector<vector<char>>& grid, int x, int y){
       // 越界,或者不为1,那么就不需要感染
        if(x < 0  || x >= grid.size() || y < 0 || y >= grid[0].size() || grid[x][y] != '1'){
            return;
        }
        
        grid[x][y] = '0';  //grid[x][y] = '2'
        infect(grid, x - 1, y);
        infect(grid, x + 1, y);
        infect(grid, x, y - 1);
        infect(grid, x, y + 1);
    }
public:
    int numIslands(vector<vector<char>>& grid) {
        if(grid.empty() || grid[0].empty()){
            return 0;
        }
        int ans = 0, 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'){
                    ans++;
                    infect(grid, i, j);
                }
            }
        }
        
        return ans;
    }
};

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

广度优先遍历 BFS

  • 主循环和思路一类似,不同点是在于搜索某岛屿边界的方法不同。
  • bfs 方法:
    • 借助一个队列queue,判断队列首部节点(i, j)是否未越界而且为1
      • 如果是则置(删除此岛屿),并将此节点上下左右节点(i+1,j),(i-1,j),(i,j+1),(i,j-1)加入队列
      • 如果不是则跳过此节点
    • 循环pop队列首节点,直到整个队列为空,此时已经遍历完此岛屿
class Solution {
    void bfs(vector<vector<char>>& grid, int i, int j){
        std::queue<pair<int, int>> list;
        list.push({i, j});
        while (!list.empty()){
            auto curr = list.front();list.pop();
            i = curr.first, j = curr.second;
            if(i >= 0 && i < grid.size() && j >= 0 && j < grid[0].size() && grid[i][j] == '1'){
                grid[i][j] = '0';
                list.push({i + 1, j});
                list.push({i - 1, j});
                list.push({i , j + 1});
                list.push({i , j - 1});
            }
        }
    }
public:
    int numIslands(vector<vector<char>>& grid) {
        if(grid.empty() || grid[0].empty()){
            return 0;
        }
        int ans = 0, 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'){
                    ans++;
                    bfs(grid, i, j);
                }
            }
        }

        return ans;
    }
};

在这里插入图片描述

并查集

并查集是一种树型的数据结构,用于处理一些不相交的合并以及查询问题。

步骤:

  • 遍历这个二维数组,将所有的1都认为是一个单独的集合
  • 遍历这个二维数组,对于每一个1,只看它的左边和上边,如果发现有1,就做union操作(为甚只看左边和上边,因为右边和下边是对称的,而我们从左到右,从上到下遍历,所以不会重复和遗落)
class Solution {

    
    class UnionFind{
    private:
        std::vector<int> parent;
        std::vector<int> size;
        std::vector<int> help;
        int cnt{};
        int wid;

        int index(int i, int j) const{
            return i * wid + j;         //x、y 表示二维坐标值,w 表示矩阵宽度。
        }

        int findRoot(int i){
            int hi = 0;
            while (parent[i] != i){
                help[hi++] = i;
                i = parent[i];
            }
            for (hi--;  hi >= 0; --hi) {
                parent[help[hi]] = i;
            }
            return i;
        }
    public:
        explicit UnionFind(vector<vector<char>>& board){
            int m = board.size();         // 矩阵行数
            int n = board[0].size();      // 矩阵列数(宽度),即第一行元素数
            parent.resize(m * n);
            size.resize(m * n);
            help.resize(m * n);
            wid = n;
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if(board[i][j] == '1'){
                        int idx = index(i, j);
                        parent[idx] = idx;
                        size[idx] = 1;
                        ++cnt;
                    }
                }
            }
        }

        void merge(int i1,  int j1, int i2, int j2){
            int i = index(i1, j1);
            int j = index(i2, j2);
            int ri = findRoot(i);
            int rj = findRoot(j);
            if(ri != rj){
                if(size[ri] >= size[rj]){
                    parent[rj] = ri;
                    size[ri] += size[rj];
                }else{
                    parent[ri] = rj;
                    size[rj] += size[ri];
                }
                --cnt;
            }
        }

        int count() const {
            return cnt;
        }

        bool isConnected(int i, int j){
            return findRoot(i) == findRoot(j);
        }
    };

    
public:
    int numIslands(vector<vector<char>>& board) {
        if(board.empty()){
            return 0;
        }

        int m = board.size();         // 矩阵行数
        int n = board[0].size();      // 矩阵列数(宽度),即第一行元素数

        UnionFind unionFind(board);

        // 第一列(除了(0, 0)外)
        for (int i = 1; i < m; ++i) {
            if(board[i - 1][0] == '1' && board[i][0] == '1'){
                unionFind.merge(i - 1, 0, i, 0);
            }
        }

        // 第一行(除了(0, 0)外)
        for (int j = 1; j < n; ++j) {
            if(board[0][j - 1] == '1' && board[0][j] == '1'){
                unionFind.merge(0, j - 1, 0, j);
            }
        }

        //
        for (int i = 1; i < m; ++i) {
            for (int j = 1; j < n; ++j) {
                if(board[i][j] == '1' ){  //  只看左&上
                    if(board[i - 1][j] == '1'){
                        unionFind.merge(i, j, i - 1, j);
                    }
                    if(board[i][j - 1] == '1'){
                        unionFind.merge(i, j, i, j - 1);
                    }
                }
            }
        }

        return unionFind.count();
    }
};

类似题目

题目思路
leetcode:130. 被围绕的区域 Surrounded Regions
leetcode:695. 岛屿的最大面积Max Area of Island
leetcode:463. 岛屿的周长 Island Perimeter岛屿的周长就是岛屿方格和非岛屿方格相邻的边的数量。
leetcode:200. 岛屿数量 Number of Islandsdfs、并查集
leetcode:305. 岛屿的数量 Number of Islands II 动态生成并查集
leetcode:694. 不同岛屿的数量 Number of Distinct Islands
leetcode:711.不同岛屿的数量 II Number of Distinct Islands II
leetcode:1020. 飞地的数量 number-of-enclaves
leetcode:1254. 统计封闭岛屿的数目 number-of-closed-islands只要提前把靠边的陆地都淹掉,然后算出来的就是封闭岛屿了。
leetcode:1905. 统计子岛屿 count-sub-islands
leetcode:286.给每个空房间位上填上该房间到 最近 门的距离 Walls and Gates从门开始扩散
leetcode:489. 扫地机器人 Robot Room Cleaner难点:怎么建立位置坐标?怎么回溯?
leetcode:317. 离建筑物最近的距离 Shortest Distance from All Buildings (1) 从每一个建筑物开始进行广度优先搜索 (2) 在搜索的同时计算每一个空格到这个建筑物的距离 (3) 在搜索的同时将每一个空格到每一个建筑物的距离进行累加,得到每个空格到所有建筑物的距离(4) 取空格到所有建筑物的最小距离
leetcode:323. 无向连通图中的连通分量个数Number of Connected Components in an Undirected Graph 连通图
Rotting Oranges
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值