LeetCode/岛屿数量(连通域数量)

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。

1. 遍历递归

遍历每一个位置,如果存在,则递归其周围区域,并使总区域数加一,
递归同时要四个方向都进行递归,并把递归的区域标识避免重复递归陷入死循环

遍历递归
class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        int sum = 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+'0'){
                 search(grid,i,j);
                 sum++;
                }
            }
        }
        return sum;
    }

    void search(vector<vector<char>>& grid,int i,int j){
        grid[i][j]=0+'0';
        if(i<grid.size()-1&&grid[i+1][j]=='1') search(grid,i+1,j); //往下
        if(j<grid[0].size()-1&&grid[i][j+1]=='1') search(grid,i,j+1); //往右
        if(i>0&&grid[i-1][j]=='1') search(grid,i-1,j);//往上
        if(j>0&&grid[i][j-1]=='1')   search(grid,i,j-1);//往左
    }
};

2. 并查集

并查集的方法首先要为每一个点建立集合,接着写出判断两个点是否属于一个集合的方式
最后不断合并集合,在该题中,最终集合的数量就是岛屿的数量,每合并一次岛屿数量减一
这里不考虑使用类模板的方式,因为建立集合set,set的合并,判断相邻元素属于哪个set,这些操作都会花费大量的时间和空间
直接用一个一维数组存储,每个位置的值为他们位置大小,这样就把不同集合区分开来
后面合并更新时,当他们值一样即说明是同一集合,合并时将其中一个集合元素值全部转换为另一集合元素值,即表示合并
这里我们用静态指针(索引)的方式,来方便集合的合并和元素加入

一维数组并查集
class Solution {
public:
    vector<int> parent;
    int sum;
    int numIslands(vector<vector<char>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
        int index;
        //初始化parent数组,记录初始岛屿数量
        for (int i = 0; i < m; i++)
            for(int j = 0; j < n; j++){
                index = i * n + j;
                parent.push_back(index);//后面根据索引建立集合簇
                if(grid[i][j] == '1')
                    sum++;  //记录初始岛屿数量
            }
        
        for (int i = 0; i < m; i++) 
            for (int j = 0; j < n; j++){
                index = i * n + j;  //从左往右,从上往下遍历合并全部岛屿
                if (grid[i][j] == '1') {
                    if (i+1 < m && grid[i+1][j] == '1') { //下
                        unions(index, (i + 1) * n + j);
                    }
                    if (j+1 <n && grid[i][j+1] == '1') { //右
                        unions(index, i * n + j + 1);
                    }
                }
        }
        return sum;
    }
    //find相当于自定义的一维数组指针操作
    int find(int i){ //寻找集合首索引,即集合的唯一标识符
        if (parent[i] == i) return parent[i]; //索引指向自己,表示自己是首位,返回自己
        parent[i] = find(parent[i]);  //如果自己不是,递归寻找且更新索引
        return parent[i];
    }

    void unions(int i ,int j){
        if (find(i) == find(j)) return; //已经是同一集合,避免重复合并操作
        parent[find(i)] = parent[find(j)]; //如果不是同一集合,把前面集合合并到后面集合中,即把前面集合首索引值换掉
        //此时不再指向自己,而是指向新集合首索引
        //之后的find操作会把被吞并集合索引全部更新
        sum--; //合并后总岛屿减少
    }
};
posted @ 2022-05-14 17:25  失控D大白兔  阅读(285)  评论(0编辑  收藏  举报