污染水域
题目描述:
输入一行字符串,字符串可转换为 N*N 的数组,数组可认为是一个水域,
判断多少天后,水域被全部污染。
数组中只有0和1,0表示纯净,1表示污染,
每天只可污染上下左右的水域,
如果开始全部被污染,或永远无法污染,则返回-1。
输入输出描述:
输入描述:
一行字符串
输出描述:
多少天后,水域被全部污染
示例1:
输入:
1,0,1,0,0,0,1,0,1
输出:
2
解释:
转化为数组为:
1 0 1
0 0 0
1 0 1
第一天后水域变为
1 1 1
1 0 1
1 1 1
第二天全部被污染
1 1 1
1 1 1
1 1 1
示例2:
输入:
0,0,0,0
输出:
-1
解题思路:
典型的BFS求解题目,类似的思想可以从写二叉树/多叉树的层次遍历开始,如:102. 二叉树的层序遍历、429. N 叉树的层序遍历。
宽度优先的思想就是:逐一遍历这一层节点,并且将与这些节点直接相连的节点加入到待遍历的节点队列中,本层遍历完后,队列中剩下的待遍历节点就是第二层.....
如下图,5*5的矩阵,从中间开始污染:
代码:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String[] split = scanner.nextLine().split(",");
int n = (int) Math.sqrt(split.length);
int[][] matrix = new int[n][n];
// 记录下所有点是否都已经被污染了
boolean[][] visited = new boolean[n][n];
// 污染的时候计算上下左右点的坐标
int[][] direction = new int[][] {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
// 记录污染源
Queue<int[]> pollution = new ArrayDeque<>();
// 将字符串转换成 N * N 的矩阵
for (int i = 0; i < split.length; i++) {
int value = Integer.parseInt(split[i]);
matrix[i / n][i % n] = value;
// 记录下有哪些污染源
if (value == 1) {
pollution.offer(new int[] {i / n, i % n});
visited[i / n][i % n] = true;
}
}
// 如果没有污染源,则返回 -1
if (pollution.isEmpty()) {
System.out.println(-1);
return;
}
// 每层污染源数量
int levelSize = pollution.size();
// 记录污染完所有点需要多少天
int levels = 0;
while (!pollution.isEmpty()) {
// 从一层中弹出一个污染源,将这个污染源的上下左右还未被污染的点污染掉
int[] poll = pollution.poll();
levelSize--;
// 开始污染:将这个污染源的上下左右还未被污染的点污染掉
for (int[] item : direction) {
int newX = item[0] + poll[0];
int newY = item[1] + poll[1];
// 没有越界、没有被污染,进行污染
if (newX >= 0 && newX < n && newY >= 0 && newY < n && !visited[newX][newY]) {
visited[newX][newY] = true;
pollution.add(new int[]{newX, newY});
}
}
// 一层污染源遍历结束,层数 + 1,重新初始化新的一层污染点数量
// 即一层的污染源已经完成了它们的污染任务,紧接着让被它们这一层污染掉的点作为源头去污染其他的
if (levelSize == 0) {
levels++;
levelSize = pollution.size();
}
}
System.out.println(levels - 1);
}