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);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值