LeetCode1514:概率最大的路径
给你一个由 n 个节点(下标从 0 开始)组成的无向加权图,该图由一个描述边的列表组成,其中 edges[i] = [a, b] 表示连接节点 a 和 b 的一条无向边,且该边遍历成功的概率为 succProb[i] 。
指定两个节点分别作为起点 start 和终点 end ,请你找出从起点到终点成功概率最大的路径,并返回其成功概率。
如果不存在从 start 到 end 的路径,请 返回 0 。只要答案与标准答案的误差不超过 1e-5 ,就会被视作正确答案。
示例 1:
输入: n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.2], start = 0, end = 2
输出: 0.25000
解释: 从起点到终点有两条路径,其中一条的成功概率为 0.2 ,而另一条为 0.5 * 0.5 = 0.25
示例 2:
输入: n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.3], start = 0, end = 2
输出: 0.30000
示例 3:
输入: n = 3, edges = [[0,1]], succProb = [0.5], start = 0, end = 2
输出: 0.00000
解释: 节点 0 和 节点 2 之间不存在路径
提示:
0 <= start, end < nstart != end0 <= a, b < na != b0 <= succProb[i] <= 1- 每两个节点之间最多有一条边
思路分析
首先建图,将图转为邻接表表示,并且将概率作为该边的权重一同存入邻接表中。因为本题是无向图,所以在建图的时候记得双向存储信息。 建好图之后直接套Dijkstra框架,但是本题需要求起点到终点成功概率最大的路径,所以在最开始的时候起点到起点的概率应该是1。起点到其他节点的概率因为置为一个不可能达到的值。
使用邻接矩阵记录边与点的关系,再使用bfs广度遍历出起点到各个点的距离,松弛操作后得到最大的概率(dijkstra ),最后使用大顶堆优化
算法代码
class State {
int node;
double disFromStart;
State(int node, double disFromStart) {
this.node = node;
this.disFromStart = disFromStart;
}
}
public double maxProbability(int n, int[][] edges, double[] succProb, int start, int end) {
List < double[] > [] graph = buildGraph(n, edges, succProb);
double[] disTo = new double[n];
Arrays.fill(disTo, -1);
// 起点到起点的概率
disTo[start] = 1.0;
// 大顶堆
PriorityQueue < State > pq = new PriorityQueue < > ((s1, s2) - > {
return Double.compare(s2.disFromStart, s1.disFromStart);
});
// 加入起点
pq.add(new State(start, 1.0));
while (!pq.isEmpty()) {
State curState = pq.poll();
int curNode = curState.node;
double curDis = curState.disFromStart;
// 如果已经到了终点 因为是大顶堆所以直接返回
if (curNode == end) return disTo[curNode];
// 如果当前概率小于之前存的概率 直接下一个 (因为概率肯定是越乘越小)
if (curDis < disTo[curNode]) continue;
// 邻居
for (double[] next: graph[curNode]) {
int nextNode = (int)(next[0]);
double nextpro = next[1];
// 到达下一个节点的概率等于
// 到达当前节点的概率*当前节点到下一个节点的概率
double nextDis = disTo[curNode] * nextpro;
// 如果存的概率小于最新得到的概率 则更新
if (disTo[nextNode] < nextDis) {
disTo[nextNode] = nextDis;
pq.add(new State(nextNode, nextDis));
}
}
}
return 0.0;
}
// 建图
public List < double[] > [] buildGraph(int n, int[][] edges, double[] succProb) {
List < double[] > [] graph = new LinkedList[n];
int m = edges.length;
for (int i = 0; i < n; i++) {
graph[i] = new LinkedList < > ();
}
for (int i = 0; i < m; i++) {
int from = edges[i][0];
int to = edges[i][1];
double weight = succProb[i];
// 因为是无向图 所以from-to to-from都需要存
graph[from].add(new double[] {
to * 1.0, weight
});
graph[to].add(new double[] {
from * 1.0, weight
});
}
return graph;
}
结果详情
算法复杂度
- 空间复杂度:
- 时间复杂度:
在掘金(JUEJIN)一起进步,一起成长!