LeetCode Java 队列结合广度优先算法(BFS)实现岛屿个数计算,附带详细分析
理解:不吐槽了。。。
分析:借由广度优先算法的思想,先循环根节点的海域,接着是根节点外面的第一层海域,然后是与第一层相邻的第二层海域,以此类推,探索过的位置不需要探索,直到探索完全部海域。
如果用树的形式来解释,就是按照:A➡B➡C➡D➡E➡F➡G 的顺序去探索
实现:接下来就是具体的实现,对于代码层面上的分析,我都详细的写在注释上了
/**
* BFS 广度优先算法实现岛屿个数探索
* @author: author
* @create: 2019-07-31 13:44
**/
public class IsLandBfs {
/**
* 判断是否是岛屿,然后统计岛屿数量
* @param isLand 未知海域数组
* @return 返回岛屿数量
*/
public static Integer isLand(int[][] isLand) {
// 都没东西玩啥
if (isLand.length == 0) {
return 0;
}
// 岛屿数量
int count = 0;
// 循环未知海域的二维数组
for (int i = 0; i < isLand.length; i ++) {
for (int j = 0; j < isLand[i].length; j ++) {
// isLand 拥有的值有:1 未探索的岛屿,0 海域,-1 已探索的岛屿
// isLand 为 1 表示这个是未探索岛屿(根节点),你也可以看作最初的登陆点
// 至于已探索岛屿肯定是与之前岛屿相连,无需重复探索
if (isLand[i][j] == 1) {
count ++;
System.out.println("岛屿登陆点(根节点),这是发现的第" + count + "座岛屿");
}
// 开始 BFS 广度优先算法探索岛屿
visitLand(isLand, i, j);
}
}
return count;
}
/**
* BFS 广度优先算法岛屿探索,从岛屿的根节点开始
* 把与这个岛屿相连的岛屿全部在 isLand 中状态变为 -1,防止重复探索
* @param isLand
* @param i
* @param j
*/
public static void visitLand(int[][] isLand, int i, int j) {
// 声明队列
Queue<Integer> queue = new LinkedList<>();
// 在后面 while 的循环中,如果是岛屿,也会陆续把这个岛屿周围的点的定位添加到队列中
// 所有点都以 先 i,后 j,的顺序添加,因此队列以 i,j 交错的形式存在
// i 与后一个 j 组成一个需要探索的位置,也可以理解成一个需要探索点的坐标
// 而探索的顺序就是从根节点开始,第一层的点全部探索完后,之后探索第二层的所有点,以此类推
// 不太理解的需要好好理解下
// 把 i 放入队列
queue.offer(i);
// 把 j 放入队列
queue.offer(j);
// 循环队列
// 每次循环都取一对 i,j,以此锁定一个需要探索的海域
while (!queue.isEmpty()) {
// 队列的 poll 方法会把队列最前面的值返回后,把这个值删除
i = queue.poll();
j = queue.poll();
// 如果这个点是海域或者已探索的岛屿都跳过
if (isLand[i][j] != 1) {
continue;
}
// 记录下这个点探索过了,把探索过的点状态变为 -1
isLand[i][j] = -1;
// 把这个点的上面点加入队列
// 这里注意:i 是循环行, j 是循环列
// 比如: i = 2,i - 1 就是从第 2 行向第 1 行去探索,是向上
// 不理解的可以好好捋一捋
if (i - 1 >= 0) {
queue.offer(i - 1);
queue.offer(j);
}
// 把这个点的下面点加入队列
if (i + 1 < isLand.length) {
queue.offer(i + 1);
queue.offer(j);
}
// 把这个点的左面点加入队列
if (j - 1 >= 0) {
queue.offer(i);
queue.offer(j - 1);
}
// 把这个点的右面点加入队列
if (j + 1 < isLand[i].length) {
queue.offer(i);
queue.offer(j + 1);
}
}
}
public static void main(String[] args) {
// 岛屿 二维数组(图形化)
int [][] isLand = {{1, 1, 0, 0, 0},{1, 1, 0, 0, 0},{0, 0, 1, 0, 0},{0, 0, 0, 1, 1}};
int count = isLand(isLand);
System.out.println("一共探索到" + count + "座岛屿");
}
}
附带下队列方法解释:
add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
offer 添加一个元素并返回true 如果队列已满,则返回false
poll 移除并返问队列头部的元素 如果队列为空,则返回null
peek 返回队列头部的元素 如果队列为空,则返回null
put 添加一个元素 如果队列满,则阻塞
take 移除并返回队列头部的元素 如果队列为空,则阻塞
说实话,比起广度优先,我觉得深度优先的代码层面上更好理解一些
Java 深度优先算法(DFS)实现岛屿个数计算,附带详细分析