LeetCode200.岛屿数量dfs/bfs/并查集 java

题目描述

给定一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

示例 1:

输入:
11110
11010
11000
00000

输出: 1
示例 2:

输入:

11000
11000
00100
00011

输出: 3

思路实现

dfs

遍历每个点,将这个点附近所有1感染为2.统计岛的数量

public class Code_03_Islands {

	public static int countIslands(int[][] m) {
		if (m == null || m[0] == null) {
			return 0;
		}
		int N = m.length;
		int M = m[0].length;
		int res = 0;
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				if (m[i][j] == 1) {
					res++;
					infect(m, i, j, N, M);
				}
			}
		}
		return res;
	}

	public static void infect(int[][] m, int i, int j, int N, int M) {
		if (i < 0 || i >= N || j < 0 || j >= M || m[i][j] != 1) {
			return;
		}
		m[i][j] = 2;
		infect(m, i + 1, j, N, M);
		infect(m, i - 1, j, N, M);
		infect(m, i, j + 1, N, M);
		infect(m, i, j - 1, N, M);
	}

	public static void main(String[] args) {
		int[][] m1 = {  { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 
				        { 0, 1, 1, 1, 0, 1, 1, 1, 0 }, 
				        { 0, 1, 1, 1, 0, 0, 0, 1, 0 },
				        { 0, 1, 1, 0, 0, 0, 0, 0, 0 }, 
				        { 0, 0, 0, 0, 0, 1, 1, 0, 0 }, 
				        { 0, 0, 0, 0, 1, 1, 1, 0, 0 },
				        { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, };
		System.out.println(countIslands(m1));

		int[][] m2 = {  { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 
						{ 0, 1, 1, 1, 1, 1, 1, 1, 0 }, 
						{ 0, 1, 1, 1, 0, 0, 0, 1, 0 },
						{ 0, 1, 1, 0, 0, 0, 1, 1, 0 }, 
						{ 0, 0, 0, 0, 0, 1, 1, 0, 0 }, 
						{ 0, 0, 0, 0, 1, 1, 1, 0, 0 },
						{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }, };
		System.out.println(countIslands(m2));

	}

}

bfs

public static int numIslands(int[][] matrix) {
        if (matrix == null || matrix[0].length == 0) return 0;

        int N = matrix.length;
        int M = matrix[0].length;
        int nums = 0;

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (matrix[i][j] == 1) {
                    nums++;
                    matrix[i][j] = 0;
                    Queue<Integer> neighbor = new LinkedList<>();
                    neighbor.add(i * M + j);
                    while (!neighbor.isEmpty()) {
                        int id = neighbor.remove();
                        int row = id / M;
                        int col = id % M;
                        if (row - 1 >= 0 && matrix[row - 1][col] == 1) {
                            neighbor.add((row - 1) * M + col);
                            matrix[row - 1][col] = 0;
                        }
                        if (row + 1 < N && matrix[row + 1][col] == 1) {
                            neighbor.add((row + 1) * M + col);
                            matrix[row + 1][col] = 0;
                        }
                        if (col - 1 >= 0 && matrix[row][col - 1] == 1) {
                            neighbor.add(row * M + col - 1);
                            matrix[row][col - 1] = 0;
                        }
                        if (col + 1 < M && matrix[row][col + 1] == 1) {
                            neighbor.add(row * M + col + 1);
                            matrix[row][col + 1] = 0;
                        }
                    }
                }
            }
        }
        return nums;
    }

拓展

当题目变的更为复杂,矩阵极为庞大,但有多个CPU怎么处理。

将大矩阵通过划分成多个小矩阵,通过hash分配给多个cpu。分别计算出每个矩阵的岛数量再合并。

此时会出现问题,在划分过程中会把一个连续小岛划分在两个或多个区域中。这样小矩阵在合并的时候会出现重复统计的问题?

此时使用并查集解决问题
需要记录当前小矩阵岛数量加小矩阵边界的水陆情况,在使用dfs标记的过程中,标记它是由谁触发被标记的(记录根节点)。

拿两个小岛举例:
在这里插入图片描述
左边小矩阵最右列和右边小矩阵的最左列是边界情况,在合并矩阵的过程中需要考虑“去重”。左边最右列的上面两个“1”是由矩阵第一个“1”触发标记的,所以记录他们的根为A。同理下面两个“1”记录根为B,右边矩阵的最左列都是由同一个“1”触发标记,所以根为C。

第一行两个1,属于不同的根A与C,说明以前没有合并过,现在进行合并,岛数量本来是左2+右2=4个,4-1=3个。
再看第二行,第二行的根也是A和C,但是第一步已经合并过了AC现在同属于一个集合。岛的数量不需要减1
第三行,一个0一个1,他们不连续,不需要考虑
第四行,两个1,分别属于B和C,需要进行合并,岛的数量减1,由3变为2.
第五行,一个0一个1,不管。
所以整个岛的数量为4-1-1 = 2。

由两个矩阵可以拓展到更多矩阵的合并,需要知道每个矩阵岛的数量,以及对每个矩阵岛的四周边界信息,就可以进行合并。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值