文章目录
- 多源BFS
- [1. 01矩阵(LC 542)](#1. 01矩阵(LC 542))
- [2. 飞地的数量(LC 1020)](#2. 飞地的数量(LC 1020))
- [3. 地图中的最高点(LC 1765)](#3. 地图中的最高点(LC 1765))
- [4. 地图分析(LC 1162)](#4. 地图分析(LC 1162))
多源BFS
解决多个源头的权值为1的最短路径问题。
- 暴力解法:细化为多个单源BFS,取最小值,大概率会超时。
- 把所有源点看作一个"超级源点",问题就变成了单源最短路径问题。只需要从超级源点开始进行一次BFS就可以得到结果
- 把所有起点加入到队列里,开始BFS搜索
1. 01矩阵(LC 542)
题目描述

解题思路
如果把1当作起点,找到0以后还要回退到源点,比较复杂;正难则反,把0当作起点,到达终点后可以直接记录步数。
代码实现
java
class Solution {
public int[][] updateMatrix(int[][] mat) {
Queue<int[]> queue = new LinkedList<>();
int m = mat.length;
int n = mat[0].length;
int[][] ret = new int[m][n];
int[] dx = { 0, 0, 1, -1 };
int[] dy = { 1, -1, 0, 0 };
//初始化为-1,标记当前位置没有被搜索过
for (int[] arr : ret)
Arrays.fill(arr, -1);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (mat[i][j] == 0) {
ret[i][j] = 0;
queue.offer(new int[] { i, j });
}
}
}
//这里不需要求队列大小,也不需要step统计,直接在原来的基础上+1就是新的步数
while (!queue.isEmpty()) {
int[] top = queue.poll();
int ii = top[0];
int jj = top[1];
for (int k = 0; k < 4; k++) {
int x = dx[k] + ii;
int y = dy[k] + jj;
if (x >= 0 && x < m && y >= 0 && y < n && ret[x][y] == -1){
queue.offer(new int[]{x,y});
ret[x][y] = ret[ii][jj]+1;
}
}
}
return ret;
}
}
2. 飞地的数量(LC 1020)
题目描述

解题思路
正难则反,直接从边界开始向内搜索,所有被遍历到的1都是可以移动出去的;再依次遍历数组,BFS中未被遍历的1就是答案。
代码实现
java
class Solution {
public int numEnclaves(int[][] grid) {
int[] dx = {0,0,1,-1};
int[] dy = {1,-1,0,0};
int m = grid.length;
int n = grid[0].length;
boolean[][] vis = new boolean[m][n];
Queue<int[]> queue = new LinkedList();
int ret = 0;
//检索边缘1
for(int i = 0;i<m;i++){
if(grid[i][0]==1){
queue.offer(new int[]{i,0});
vis[i][0] = true;
}
if(grid[i][n-1]==1){
queue.offer(new int[]{i,n-1});
vis[i][n-1] = true;
}
}
for(int j = 0;j<n;j++){
if(grid[0][j]==1){
queue.offer(new int[]{0,j});
vis[0][j] = true;
}
if(grid[m-1][j]==1){
queue.offer(new int[]{m-1,j});
vis[m-1][j] = true;
}
}
//多源BFS
while(!queue.isEmpty()){
int[] top = queue.poll();
int ii = top[0];
int jj = top[1];
for(int k = 0;k<4;k++){
int x = ii+dx[k];
int y = jj+dy[k];
if(x>=0 && x<m && y>=0 && y<n && !vis[x][y] && grid[x][y] == 1){
vis[x][y] =true;
queue.offer(new int[] {x,y});
}
}
}
for(int i = 0;i<m ;i++){
for(int j = 0;j<n;j++){
if(!vis[i][j] && grid[i][j] == 1)
ret++;
}
}
return ret;
}
}
3. 地图中的最高点(LC 1765)
题目描述

解题思路
从0开始,向周围逐步+1扩展
代码实现
java
class Solution {
public int[][] highestPeak(int[][] isWater) {
int m = isWater.length;
int n = isWater[0].length;
int[] dx = {0,0,1,-1};
int[] dy = {1,-1,0,0};
int[][] ret = new int[m][n];
for(int[] arr:ret)
Arrays.fill(arr,-1);
Queue<int[]> queue = new LinkedList<>();
for(int i = 0;i<m;i++){
for(int j = 0;j<n;j++){
if(isWater[i][j] == 1){
queue.offer(new int[]{i,j});
ret[i][j] = 0;
}
}
}
while(!queue.isEmpty()){
int[] top = queue.poll();
int ii = top[0];
int jj = top[1];
for(int k=0;k<4;k++){
int x = ii +dx[k];
int y = jj +dy[k];
if(x>=0 && x<m && y >=0 && y<n && ret[x][y]==-1 && isWater[x][y]==0){
queue.offer(new int[]{x,y});
ret[x][y] = ret[ii][jj] +1;
}
}
}
return ret;
}
}
4. 地图分析(LC 1162)
题目描述

解题思路
从1开始多源BFS,利用数组记录距离。题中的曼哈顿距离与步长相等。
代码实现
java
class Solution {
public int maxDistance(int[][] grid) {
int[] dx = {0,0,1,-1};
int[] dy = {1,-1,0,0};
int m = grid.length;
int n = grid[0].length;
int[][] dest = new int[m][n];
for(int[] arr:dest)
Arrays.fill(arr,-1);
Queue<int[]> queue = new LinkedList<>();
for(int i = 0;i<m;i++){
for(int j = 0;j<n;j++){
if(grid[i][j]==1){
queue.offer(new int[]{i,j});
dest[i][j] = 0;
}
}
}
int ret = -1;
while(!queue.isEmpty()){
int[] top = queue.poll();
int a = top[0];
int b = top[1];
for(int k = 0;k<4;k++){
int x = a+dx[k];
int y = b+dy[k];
if(x>=0 && x<m && y>=0 && y<n && dest[x][y]==-1 ){
dest[x][y] = dest[a][b] + 1;
queue.offer(new int[]{x,y});
ret = Math.max(ret,dest[x][y]);
}
}
}
return ret;
}
}