leetcode1514. 概率最大的路径
首先考虑了dfs,1000节点超时,添加记忆化,5000节点超出空间。
邻接矩阵->邻接表(HashMap<node,HashMap>)解决空间问题
dfs仍然超时。
尝试bfs + 普通队列,结果存在误差:由于多次相乘,导致最终结果精度存在问题。
bfs+优先队列+剪枝:将概率大的进行优先排列,保证最短时间找到结果,将小于当前结果的路径排除(剪枝)。
class Solution { // 最短路径问题:bfs 队列 // dfs会一条路找到头,因此产生不必要的误差,且剪枝复杂 // 使用优先队列,优先计算大的通路 public double maxProbability(int n, int[][] edges, double[] succProb, int start, int end) { Map<Integer, Map<Integer, Double>> allEdge = new HashMap<>(); // 初始化邻接表 for (int i = 0; i < edges.length; i++) { int x = edges[i][0], y = edges[i][1]; double val = succProb[i]; Map<Integer, Double> temp; if (!allEdge.containsKey(x)) { temp = new HashMap<>(); // temp.put(x, 1.0); } else { temp = allEdge.get(x); } temp.put(y, val); allEdge.put(x, temp); if (!allEdge.containsKey(y)) { temp = new HashMap<>(); // temp.put(y, 1.0); } else { temp = allEdge.get(y); } temp.put(x, val); allEdge.put(y, temp); } // 判断边界 if (!allEdge.containsKey(start) || !allEdge.containsKey(end)) { return 0.0; } // 非记忆法会超时,因此使用一个记忆表记录到达某个节点的最大值 Map<Integer, Double> memMap = new HashMap<>(); memMap.put(start, 1.0); Set<Integer> used = new HashSet<>(); used.add(start); // Queue<Integer> queue = new ArrayDeque<>(); Queue<Node> pq = new PriorityQueue<Node>((o1,o2)->{ if(o2.maxVal-o1.maxVal>0){ return 1; }else{ return -1; } }); pq.add(new Node(start,1.0)); while (!pq.isEmpty()) { Node temp = pq.poll(); int outNode = temp.node; used.add(outNode); // 遍历与outNode相连的所有节点 for (Map.Entry<Integer, Double> relateMap : allEdge.get(outNode).entrySet()) { Integer node = relateMap.getKey(); double val = relateMap.getValue(); // 如果没来过,或者来过但本次比较大,那么更新 if (memMap.containsKey(node)) { // 如果当前值比较小 double curVal = val * memMap.get(outNode), historyVal = memMap.get(node); if (curVal <= historyVal) { continue; } } memMap.put(node, val * memMap.get(outNode)); // 如果node没有被poll过,可以放入,如果当前的node概率小于最终的答案,那么不加入 if (!used.contains(node) ) { // 当已经找到答案了,就不用往队列里加比答案更小的路径了,因为路径只会递减 if(memMap.containsKey(end) && memMap.get(end)>memMap.get(node)){ continue; } pq.add(new Node(node,memMap.get(node))); } } } if(!memMap.containsKey(end)){ return 0.0; } return memMap.get(end); } class Node{ int node; double maxVal; public Node(int node, double maxVal){ this.node = node; this.maxVal = maxVal; } } } // class Solution { // public double maxProbability(int n, int[][] edges, double[] succProb, int start, int end) { // Map<Integer,Map<Integer,Double>> allEdge = new HashMap<>(); // // 初始化邻接表 // for(int i=0; i<edges.length; i++){ // int x=edges[i][0], y = edges[i][1]; // double val = succProb[i]; // Map<Integer,Double> temp; // if(!allEdge.containsKey(x)){ // temp = new HashMap<>(); // // temp.put(x,1.0); // }else{ // temp = allEdge.get(x); // } // // System.out.println("x="+x+",y="+y+",val="+val); // temp.put(y,val); // allEdge.put(x,temp); // if(!allEdge.containsKey(y)){ // temp = new HashMap<>(); // // temp.put(y,1.0); // }else{ // temp = allEdge.get(y); // } // // System.out.println("y="+y+",x="+x+",val="+val); // temp.put(x,val); // allEdge.put(y,temp); // } // // 判断边界 // if(!allEdge.containsKey(start) || !allEdge.containsKey(end) ){ // return 0.0; // } // // 非记忆法会超时,因此使用一个记忆表记录到达某个节点的最大值 // Map<Integer,Double> memMap = new HashMap<>(); // Set<Integer> used = new HashSet<>(); // used.add(start); // // 遍历与start相连的所有节点 // for (Map.Entry<Integer, Double> relateMap : allEdge.get(start).entrySet()) { // Integer node = relateMap.getKey(); // double val = relateMap.getValue(); // if(!used.contains(node)) { // // 判断是否访问过该node // if(memMap.containsKey(node)){ // //如果访问过,且当前节点的值小于曾经访问,那么直接退出 // if(val<=memMap.get(node)){ // continue; // } // } // memMap.put(node,val); // used.add(node); // dfs(node, end, used, val, allEdge,memMap); // used.remove(node); // } // } // return maxVal; // } // double maxVal=0; // private void dfs(int curNode, int end, Set<Integer> used, double curVal, Map<Integer, Map<Integer, Double>> allEdge, Map<Integer, Double> memMap) { // if(curNode == end){ // maxVal = Math.max(maxVal,curVal); // return; // } // for (Map.Entry<Integer, Double> relateMap : allEdge.get(curNode).entrySet()) { // Integer node = relateMap.getKey(); // double val = relateMap.getValue(); // // 判断node是否可以通行 // if(!used.contains(node)) { // // 判断是否访问过该node // if(memMap.containsKey(node)){ // //如果访问过,且当前节点的值小于曾经访问,那么直接退出 // if(val*curVal<=memMap.get(node)){ // continue; // } // } // memMap.put(node,val*curVal); // used.add(node); // dfs(node, end, used, val*curVal, allEdge, memMap); // used.remove(node); // } // } // } // }