提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
Dijkstra 算法(一般音译成迪杰斯特拉算法)无非就是一个 BFS 算法的加强版,它们都是从二叉树的层序遍历衍生出来的。
一、力扣1631. 最小体力消耗路径
class Solution {
public int minimumEffortPath(int[][] heights) {
int m = heights.length, n = heights[0].length;
// 定义:从 (0, 0) 到 (i, j) 的最小体力消耗是 effortTo[i][j]
int[][] effortTo = new int[m][n];
// dp table 初始化为正无穷
for (int i = 0; i < m; i++) {
Arrays.fill(effortTo[i], Integer.MAX_VALUE);
}
// base case,起点到起点的最小消耗就是 0
effortTo[0][0] = 0;
// 优先级队列,effortFromStart 较小的排在前面
Queue<State> pq = new PriorityQueue<>((a, b) -> {
return a.effortFromStart - b.effortFromStart;
});
// 从起点 (0, 0) 开始进行 BFS
pq.offer(new State(0, 0, 0));
while (!pq.isEmpty()) {
State curState = pq.poll();
int curX = curState.x;
int curY = curState.y;
int curEffortFromStart = curState.effortFromStart;
// 到达终点提前结束
if (curX == m - 1 && curY == n - 1) {
return curEffortFromStart;
}
if (curEffortFromStart > effortTo[curX][curY]) {
continue;
}
// 将 (curX, curY) 的相邻坐标装入队列
for (int[] neighbor : adj(heights, curX, curY)) {
int nextX = neighbor[0];
int nextY = neighbor[1];
// 计算从 (curX, curY) 达到 (nextX, nextY) 的消耗
int effortToNextNode = Math.max(
effortTo[curX][curY],
Math.abs(heights[curX][curY] - heights[nextX][nextY])
);
// 更新 dp table
if (effortTo[nextX][nextY] > effortToNextNode) {
effortTo[nextX][nextY] = effortToNextNode;
pq.offer(new State(nextX, nextY, effortToNextNode));
}
}
}
// 正常情况不会达到这个 return
return -1;
}
// 方向数组,上下左右的坐标偏移量
int[][] dirs = new int[][]{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
// 返回坐标 (x, y) 的上下左右相邻坐标
List<int[]> adj(int[][] matrix, int x, int y) {
int m = matrix.length, n = matrix[0].length;
// 存储相邻节点
List<int[]> neighbors = new ArrayList<>();
for (int[] dir : dirs) {
int nx = x + dir[0];
int ny = y + dir[1];
if (nx >= m || nx < 0 || ny >= n || ny < 0) {
// 索引越界
continue;
}
neighbors.add(new int[]{nx, ny});
}
return neighbors;
}
class State {
// 矩阵中的一个位置
int x, y;
// 从起点 (0, 0) 到当前位置的最小体力消耗(距离)
int effortFromStart;
State(int x, int y, int effortFromStart) {
this.x = x;
this.y = y;
this.effortFromStart = effortFromStart;
}
}
}
二、力扣1514. 概率最大的路径
class Solution {
public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) {
List<double[]>[] graph = builderGraph(edges, n, succProb);
PriorityQueue<State> pq = new PriorityQueue<>(
(a,b)->{
return Double.compare(b.value, a.value);
}
);
double[] flag = new double[n];
Arrays.fill(flag,Integer.MIN_VALUE);
flag[start_node] = 1;
pq.offer(new State(start_node,1));
while(!pq.isEmpty()){
State cur = pq.poll();
int curId = cur.id;
double curValue = cur.value;
if(curValue > flag[curId]){
continue;
}
if(curId == end_node){
return curValue;
}
for(double[] nexts : graph[curId]){
int nextId = (int)nexts[1];
double nextValue = nexts[2];
if(nextValue * curValue > flag[nextId]){
flag[nextId] = nextValue * curValue;
pq.offer(new State(nextId,flag[nextId]));
}
}
}
return 0.0;
}
List<double[]>[] builderGraph(int[][] edges, int n, double[] succProb){
List<double[]>[] graph = new LinkedList[n];
for(int i = 0; i < n; i ++){
graph[i] = new LinkedList<double[]>();
}
for(int i = 0; i < edges.length; i ++){
int from = edges[i][0];
int to = edges[i][1];
graph[from].add(new double[]{from, to, succProb[i]});
graph[to].add(new double[]{to,from,succProb[i]});
}
return graph;
}
class State{
int id;
double value;
public State(int id, double value){
this.id = id;
this.value = value;
}
}
}