Leetcode1368. 使网格图至少有一条有效路径的最小代价-----Dijkstra 算法、BFS
题目表述
给你一个 m x n 的网格图 grid 。 grid 中每个格子都有一个数字,对应着从该格子出发下一步走的方向。 grid[i][j] 中的数字可能为以下几种情况:
- 1 ,下一步往右走,也就是你会从 grid[i][j] 走到 grid[i][j + 1]
- 2 ,下一步往左走,也就是你会从 grid[i][j] 走到 grid[i][j - 1]
- 3 ,下一步往下走,也就是你会从 grid[i][j] 走到 grid[i + 1][j]
- 4 ,下一步往上走,也就是你会从 grid[i][j] 走到 grid[i - 1][j]
注意网格图中可能会有 无效数字 ,因为它们可能指向 grid 以外的区域。
一开始,你会从最左上角的格子 (0,0) 出发。我们定义一条 有效路径 为从格子 (0,0) 出发,每一步都顺着数字对应方向走,最终在最右下角的格子 (m - 1, n - 1) 结束的路径。有效路径 不需要是最短路径 。
你可以花费 cost = 1 的代价修改一个格子中的数字,但每个格子中的数字 只能修改一次 。
请你返回让网格图至少有一条有效路径的最小代价。
示例:
输入:grid = [[1,1,1,1],[2,2,2,2],[1,1,1,1],[2,2,2,2]]
输出:3
解释:你将从点 (0, 0) 出发。
到达 (3, 3) 的路径为: (0, 0) --> (0, 1) --> (0, 2) --> (0, 3) 花费代价 cost = 1 使方向向下 --> (1, 3) --> (1, 2) --> (1, 1) --> (1, 0) 花费代价 cost = 1 使方向向下 --> (2, 0) --> (2, 1) --> (2, 2) --> (2, 3) 花费代价 cost = 1 使方向向下 --> (3, 3)
总花费为 cost = 3.
0-1广度优先搜索
多源BFS:从多个节点出发,每个节点入队一次,用size记录每一层的节点数,一次访问每一层的节点。多个路径同时搜索。
普通BFS:从单个节点出发,每个节点入队一次,直到找到路径
0-1BFS:在常规的广度优先搜索中,每个节点最多被添加进队列一次,而在 0-1 广度优先搜索中,每个节点最多被添加进双端队列两次(即队首一次,队尾一次)。因为我们求的是最短路径,所以当第一次出队列时,就将该节点标记为已读,第二次出队列时就不用再处理了。英雌需要用到visited数组记录,和Dijkstra 算法很相似。
class Solution {
public int minCost(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
Deque<int[]> que = new ArrayDeque<>();
que.add(new int[]{0,0});
int[][] dirs = new int[][]{{0,1},{0,-1},{1,0},{-1,0}};
int[][] dis = new int[m][n];
for(int i = 0; i < m;i++){
Arrays.fill(dis[i], Integer.MAX_VALUE);
}
dis[0][0] = 0;
boolean[][] visited = new boolean[m][n];
while(!que.isEmpty()){
int[] cur = que.poll();
int curx = cur[0];
int cury = cur[1];
if(visited[curx][cury]) continue;
visited[curx][cury] = true;
int i = 1;
for (int[] dir:dirs){
int x = dir[0] + curx;
int y = dir[1] + cury;
if(x < 0 || y<0|| x >= m || y>=n) continue;
int cost = i == grid[curx][cury] ? 0 : 1;
if(dis[curx][cury] + cost <= dis[x][y])
dis[x][y] = dis[curx][cury] + cost;
else continue;
if (cost == 0){
que.addFirst(new int[]{x,y});
}else{
que.addLast(new int[]{x,y});
}
i++;
}
}
return dis[m-1][n-1];
}
}
Dijkstra 算法
class Solution {
public int minCost(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[][] dis = new int[m][n];
for(int i = 0; i < m; i++){
Arrays.fill(dis[i], Integer.MAX_VALUE);
}
dis[0][0] = 0;
boolean[][] visited = new boolean[m][n];
int[][] dirs = {{0,1}, {0,-1},{1,0}, {-1,0}};
PriorityQueue<int[]> que = new PriorityQueue<>((a,b)->{return a[2] - b[2];});
que.offer(new int[]{0,0,0});
while(!que.isEmpty()){
int[] cur = que.poll();
if(visited[cur[0]][cur[1]]) continue;
visited[cur[0]][cur[1]] = true;
for(int i = 1;i <= 4;i++){
int x = dirs[i-1][0] + cur[0];
int y = dirs[i-1][1] + cur[1];
if(x < 0 || y < 0 || x>= m || y>= n) continue;
int cost = 0;
if(i != grid[cur[0]][cur[1]]) cost = 1;
if(cost + cur[2] < dis[x][y]){
dis[x][y] = cost + cur[2];
que.offer(new int[]{x,y,dis[x][y]});
}
}
}
return dis[m-1][n-1];
}
}