Leetcode 200. Number of Islands

Given a 2d grid map of '1’s (land) and '0’s (water), count 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.

在这里插入图片描述

method 1 DFS

使用深度优先搜索,每次递归往四个方向继续搜索递归,并且本题可以修改所给数组,从而避免使用visited数组标记已经访问过的元素

void helper(vector<vector<char>>& grid, int i, int j){
	if (i == -1 || j == -1 || i == grid.size() || j == grid[i].size()) return;
	if (grid[i][j] == '0') return;

	grid[i][j] = '0';

	helper(grid, i + 1, j);
	helper(grid, i - 1, j);
	helper(grid, i, j + 1);
	helper(grid, i, j - 1);

	
}

int numIslands2(vector<vector<char>>& grid) {
	int nums = 0;
	for (int i = 0; i < grid.size(); i++)
	{
		for (int j = 0; j < grid[i].size(); j++)
		{
			if (grid[i][j] == '1'){
				nums++;
				helper(grid, i, j);
			}
		}
	}

	return nums;
}

method 2 union find

使用并查集,将所有岛并到一起,当遍历某个点的时候,如果其四个方向中有一个方向是岛,那么就将他们并到一起

并查集注意点:

  1. 并查集的核心在于并查集数组、find方法和union方法,使用并查集的时候,要考虑好什么时候union,并且union时,要清楚谁作父结点,谁作子结点
  2. 并查集数组中存储的都是父结点的索引值,而不是结点自身的值,所以要将所给数组和并查集数组之间对应起来,像本题直接使用数组索引的计算方法映射过去,像另外一道题Leetcode_128_LongestConsecutiveSequence,就要使用map映射值和并查集数组中的位置
  3. 本题提供了一个记录并查集中有几颗树的方法:使用一个计数器,一开始遇到每一个结点,就加一,但union时就减一,最后的值即树的个数
 vector<int> par;
int islands = 0;

int find(int x){
	if (par[x] == x) return x;
	par[x] = find(par[x]);
	return par[x];
}

void union_(int id1, int id2){
	int par1 = find(id1);
	int par2 = find(id2);
	if (par1 != par2){
		par[par2] = par1;
        islands--;
	}

}


int numIslands(vector<vector<char>>& grid) {
	if(grid.size() == 0) return 0;
    int m = grid.size(), n = grid[0].size();
	int dirc[] = { 0, 1, 0, -1, 0 };
    for(int i = 0; i < m; i++){
        for(int j = 0; j < n; j++){
            if(grid[i][j] == '1') {
                islands++;
                par.push_back(i*n+j);
            }else par.push_back(-1);
        }
    }

	for (int i = 0; i < grid.size(); i++){
		for (int j = 0; j < grid[i].size(); j++)
		{
			if (grid[i][j] == '1'){
				for (int k = 0; k < 4; k++)
				{
					int x = i + dirc[k], y = j + dirc[k + 1];
					if (x >= 0 && y >= 0 && x < m && y < n && grid[x][y] == '1'){
						union_(i*n + j, x*n + y);
					}
				}

			}
		}
	}
	return islands;
}

summary

  1. 修改原数组为其他值,可节省访问数组的空间使用
  2. 并查集总结点
  3. 在二维数组中,遍历方向的简便方法:
int dirc[] = { 0, 1, 0, -1, 0 };
for (int k = 0; k < 4; k++){
	int x = i + dirc[k], y = j + dirc[k + 1];
	if (x >= 0 && y >= 0 && x < m && y < n && grid[x][y] == '1'){
			union_(i*n + j, x*n + y);
	}
}
发布了93 篇原创文章 · 获赞 9 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章