力扣-200-岛屿数量

直达链接

岛屿数量

官方题解

那么在这里,题解1深度优先和题解2广度优先的区别在哪里呢?

深度优先遍历DFS

深度优先从一个节点开始,只要上下左右有一个为陆地就回向下递归,最终类似于一个树的递归结构
会有一个dfs辅助函数用于递归

	/*
	* 思路是这样:
	* 遍历每一个单位点,如果遇到陆地就计数并开始dfs:将与这个陆地相连的所有陆地标记为0
	*/
private:
	int count = 0;
public:
	void dfs(vector<vector<char>>& grid, int i, int j, int m, int n) {
		if (i < 0 || i >= m || j < 0 || j >= n)return;
		if (grid[i][j] == '0') return;
		// 剩下就只有是1的情况
		grid[i][j] = '0';
		dfs(grid, i - 1, j, m, n);
		dfs(grid, i + 1, j, m, n);
		dfs(grid, i, j - 1, m, n);
		dfs(grid, i, j + 1, m, n);
	}

	int numIslands(vector<vector<char>>& grid) {
		int m = grid.size();
		int n = grid[0].size();
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				// 遍历每一个位置,如果是陆地就开始DFS标记
				if (grid[i][j] == '1') {
					dfs(grid, i, j, m, n);
					count++;
				}
			}
		}
		return count;
	}

广度优先遍历BFS

广度优先则是,每访问到一个为1的节点,就把它置零并放入队列,
只要队列不为空,取出一个,并把它上下左右这一圈中为1的放入队列,并且置0,实现一种“扩散”效果

那么,为什么需要这个队列?
因为要用它实现广度优先

并查集

并查集数据结构则是完美契合了这个题,一个岛屿就可以看作是一个1的并查集,那么岛屿的数量就是其中并查集的数量
要做的是扫描整个二维数组,将相连的1做“并”操作
实现,看来放入操作既不是深度也不是广度,它只会把上下左右为1的并入当前并查集,没有继续操作就直接往下访问下一个节点,但是只有在节点为1的时候才会创建新的并查集

class UnionFind {
private:
    int count;// 用来记录树(即并查集)的个数
    vector<int> parent;// 并查集的底层数组
    vector<int> rank;// 秩,用来记录以各个数组元素为根节点的树的高度

public:
    // 初始化方法
    UnionFind(vector<vector<char>>& grid) {
        count = 0;
        int m = grid.size();
        int n = grid[0].size();
        // 扫描一遍整个二维数组,将值为1的插入并计数
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == '1') {
                    // 为什么插入的是i*n+j?这是什么意思
                    // 这里是对一个二维数组构建并查集,就不能用下标值与下标相等的对应关系了
                    // 不对,这里的i*n+j还真不是乱写的,能将二维数组的双下标转换为一排一排顺序数来的下标
                    // 这样就又能够做到下标值与下标一致
                    parent.push_back(i * n + j);
                    ++count;// 那这里岂不是有几个1,count就是几
                    // 是,但是后面每一次并操作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);
            }
            // y的根节点认x的根节点为根
            parent[rooty] = rootx;// 这是什么意思,把y的根节点的值改了,那么和下标就不一致了,就不是根节点了
            // 为什么要加上这一句
            // 如果他俩一样,仍然会有y被合并到x上面,那么x的高度加一
            if(rank[rootx]==rank[rooty]) rank[rootx]+=1;
            --count;// 合并后并查集数量减一
        }
    }

    int getCount() {
        return count;
    }
};

class Solition {
public:
    int numIslands(vector<vector<char>>& grid) {
        int nr = grid.size();
        if (!nr) return 0;
        int nc = grid[0].size();

        UnionFind uf(grid);

        for (int r = 0; r < nr; ++r) {
            for (int c = 0; c < nc; ++c) {
                if (grid[r][c] == '1') {
                    grid[r][c] = '0';// 置零,避免被后续重复操作
                    // if中的第一个条件是判断是否越界的
                    // 如果上下左右某个位置为1,那么就将它与并查集合并
                    // 听说这里可以只判断两个方向
                    if (r - 1 >= 0 && grid[r - 1][c] == '1') uf.unite(r * nc + c, (r - 1) * nc + c);
                    if (r + 1 < nr && grid[r + 1][c] == '1') uf.unite(r * nc + c, (r + 1) * nc + c);
                    if (c - 1 >= 0 && grid[r][c - 1] == '1') uf.unite(r * nc + c, r * nc + c - 1);
                    if (c + 1 < nc && grid[r][c + 1] == '1') uf.unite(r * nc + c, r * nc + c + 1);
                }
            }
        }
        return uf.getCount();
    }
};
posted @ 2022-07-19 17:21  YaosGHC  阅读(70)  评论(0)    收藏  举报