LeetCode 1514.概率最大的路径 Java

1514. 概率最大的路径

难度 中等

给你一个由 n 个节点(下标从 0 开始)组成的无向加权图,该图由一个描述边的列表组成,其中 edges[i] = [a, b] 表示连接节点 a 和 b 的一条无向边,且该边遍历成功的概率为 succProb[i]

指定两个节点分别作为起点 start 和终点 end ,请你找出从起点到终点成功概率最大的路径,并返回其成功概率。

如果不存在从 startend 的路径,请 返回 0 。只要答案与标准答案的误差不超过 1e-5 ,就会被视作正确答案。

示例 1:

img

输入: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:

img

输入:n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.3], start = 0, end = 2
输出:0.30000

示例 3:

img

输入:n = 3, edges = [[0,1]], succProb = [0.5], start = 0, end = 2
输出:0.00000
解释:节点 0 和 节点 2 之间不存在路径

提示:

  • 2 <= n <= 10^4
  • 0 <= start, end < n
  • start != end
  • 0 <= a, b < n
  • a != b
  • 0 <= succProb.length == edges.length <= 2*10^4
  • 0 <= succProb[i] <= 1
  • 每两个节点之间最多有一条边
class Solution {
    class Edge {
        public int from;
        public int to;
        public double prob;

        public Edge(int from, int to, double prob) {
            this.from = from;
            this.to = to;
            this.prob = prob;
        }
    }
    public double maxProbability(int n, int[][] edges, double[] succProb, int start, int end) {
        //在1000个点时会超时
        Map<Integer, List<Edge>> graph = new HashMap<>();
        double[] maxProb = new double[n];
        for(int j=0;j<n;j++) graph.put(j, new LinkedList<>());
        for (int i = 0; i < edges.length; i++) {
            //有则add
            graph.get(edges[i][0]).add(new Edge(edges[i][0], edges[i][1], succProb[i]));
            graph.get(edges[i][1]).add(new Edge(edges[i][1], edges[i][0], succProb[i]));
        }
        if(graph.get(start)==null) return 0;
        Queue<Edge> queue = new LinkedList<>();
        queue.addAll(graph.get(start));
        maxProb[start]=1;
        double curProb=1;
        while (!queue.isEmpty()) {
            Edge edge = queue.poll();
            //当前概率=到达前一个点的最大概率*当前路径(边)的概率
            curProb = maxProb[edge.from]* edge.prob;;
            //若已经到达了终点,比较当前概率是否为最大概率
            if(edge.to==end) maxProb[end] = Math.max(curProb,maxProb[end]);
            //如果当前点没有边或者当前概率小于从其他路径到达点的概率
            if (graph.get(edge.to)==null||curProb < maxProb[edge.to]) {
                
            } else {
                //当前概率最大
                queue.addAll(graph.get(edge.to));
                maxProb[edge.to] = curProb;
            }
        }
        return maxProb[end];
    }

}

最开始的思路就是用BFS,用一个double数组maxProb 来维护从start出发到每个点的最大概率,并且在遍历途中不断更新该数组,直到BFS遍历完,返回数组中到达终点的最大概率即可。

但是在1000个点时,算法超时。

之后看了题解,之前的算法需要计算所有的边的概率,导致了时间复杂度过高,实际上可以使用Dijkstra算法了。简单介绍一下 Dijkstra算法是单源最短路算法,不能处理带负边权的情况,一般用邻接矩阵或邻接表存图,其原理基于一个前提:对于一个顶点 A 最短的邻接边 B,从 A 到 B 不可能找到比 AB 更短的路径,因为 AB 已经是最短的了,从其它路径走的话必然经过比 AB 更长的路径。

进阶上可以使用优先队列,减少了自己需要实现找到的最短路径的代码量。

public double maxProbability(int n, int[][] edges, double[] succProb, int start, int end) {
        
        Map<Integer, List<Edge>> graph = new HashMap<>();
        double[] maxProb = new double[n];
        for (int j = 0; j < n; j++) graph.put(j, new LinkedList<>());
        for (int i = 0; i < edges.length; i++) {
            graph.get(edges[i][0]).add(new Edge(edges[i][0], edges[i][1], succProb[i]));
            graph.get(edges[i][1]).add(new Edge(edges[i][1], edges[i][0], succProb[i]));
        }
        if (graph.get(start) == null) return 0;
    	//使用优先队列,因为求的是最大概率所以比较函数改成如下所示,大的在前
        PriorityQueue<Edge> queue = new PriorityQueue<>((Edge a, Edge b) -> Double.compare(b.prob, a.prob));
        queue.offer(new Edge(start,start,1));
    	//visited数组,标记是否访问过该点
        int[] visited = new int[n];
        double curProb;
        while (!queue.isEmpty()) {
            Edge poll = queue.poll();
            //如果已经访问过,跳过
            if (visited[poll.to] == 1) continue;
            //到达终点返回
            if (poll.to == end) return poll.prob;
            visited[poll.to] = 1;
            if (graph.get(poll.to) == null) {

            } else {
                //如果没到达终点且当前点存在路径通往其他点
               for(Edge edge:graph.get(poll.to)){
                   //更新概率,prob是从start到edge.to的概率
                   edge.prob = poll.prob*edge.prob;
                   //加入优先队列,概率最大的会在队列顶端,时间复杂度(nlogn)
                   //Priority queue represented as a balanced binary heap
                   queue.offer(edge);
               }

            }
        }
        return 0;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值