zoukankan      html  css  js  c++  java
  • 399. Evaluate Division

    Equations are given in the format A / B = k, where A and B are variables represented as strings, and k is a real number (floating point number). Given some queries, return the answers. If the answer does not exist, return -1.0.

    Example:
    Given a / b = 2.0, b / c = 3.0. 
    queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? . 
    return [6.0, 0.5, -1.0, 1.0, -1.0 ].

    The input is: vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries, where equations.size() == values.size(), and the values are positive. This represents the equations. Return vector<double>.

    According to the example above:

    equations = [ ["a", "b"], ["b", "c"] ],
    values = [2.0, 3.0],
    queries = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ]. 

    The input is always valid. You may assume that evaluating the queries will result in no division by zero and there is no contradiction.

    M1: graph + dfs

    有向图,A/B=2 -> g[A][B] = 2.0, g[B][A] = 1/2.0,A/C = g[A][B] * g[B][C]

    先建立graph,注意权重的处理。遍历query,只要有一个点不在graph里,就返回-1;如果两个点都在graph里,建立一个set防止重复访问,然后用dfs。dfs函数的递归终止条件是A = B,如果A不等于B,遍历A所有的邻居,如果当前邻居C已经访问过,continue;如果没有访问过,调用dfs(C, B),如果返回值 > 0,说明存在路径,返回d * g[A][C],即 C/B * A/C = A/B,如果没有符合条件的邻居,返回-1.

    时间:O(E + Q*E),空间:O(E)

    class Solution {
        public double[] calcEquation(String[][] equations, double[] values, String[][] queries) {
            HashMap<String, HashMap<String, Double>> graph = new HashMap<>();
            for(int i = 0; i < equations.length; i++) {
                graph.putIfAbsent(equations[i][0], new HashMap<>());
                graph.putIfAbsent(equations[i][1], new HashMap<>());
                graph.get(equations[i][0]).put(equations[i][1], values[i]);
                graph.get(equations[i][1]).put(equations[i][0], 1.0 / values[i]);
            }
            
            double[] res = new double[queries.length];
            for(int i = 0; i < queries.length; i++) {
                if(!graph.containsKey(queries[i][0]) || !graph.containsKey(queries[i][1])) {
                    res[i] = -1.0;
                    continue;
                }
                Set<String> visited = new HashSet<>();
                res[i] = dfs(queries[i][0], queries[i][1], graph, visited);
            }
            return res;
        }
        
        // return A/B
        private double dfs(String A, String B, HashMap<String, HashMap<String, Double>> g, Set<String> visited) {
            if(A.equals(B)) return 1.0;
            visited.add(A);
            for(String C : g.get(A).keySet()) {
                if(visited.contains(C)) continue;
                double d = dfs(C, B, g, visited);       // d = C/B
                if(d > 0) return d * g.get(A).get(C);   // return C/B * A/C = A/B
            }
            return -1.0;
        }
    }

    follow up:如果查询次数很多怎么提高效率 

    M2: union find

    query很多的时候,因为uf中的路径经过压缩,平均时间O(1)(BFS每次query都要搜一遍图,query多时效率不高)。

    时间:O(E + Q),空间:O(E)

    class Solution {
        // parents["A"] = "B", val["A"] = 2.0} -> A = B * 2.0 -> A/B = 2.0
        HashMap<String, String> parents = new HashMap<>();
        HashMap<String, Double> val = new HashMap<>();
        public double[] calcEquation(String[][] equations, double[] values, String[][] queries) {
            double[] res = new double[queries.length];
            for(int i = 0; i < equations.length; i++) {
                String A = equations[i][0];
                String B = equations[i][1];
                double k = values[i];
                if(!parents.containsKey(A) && !parents.containsKey(B)) {
                    parents.put(A, A);
                    parents.put(B, B);
                    val.put(A, k);
                    val.put(B, 1.0);
                } else if(!parents.containsKey(A)) {
                    parents.put(A, A);
                    val.put(A, val.get(B) * k);
                } else if(!parents.containsKey(B)) {
                    parents.put(B, B);
                    val.put(B, val.get(A) / k);
                } else {
                    String rA = find(A);
                    for (String key: parents.keySet()) {
                        if (find(key).equals(rA)) {
                            val.put(key, val.get(key) * k * val.get(B));
                        }
                    }
                }
                union(A, B);
            }
            
            for(int i = 0; i < queries.length; i++) {
                String X = queries[i][0], Y = queries[i][1];
                if (!val.containsKey(X) || !val.containsKey(Y) || !find(X).equals(find(Y)))
                    res[i] = -1.0;
                else
                    res[i] = val.get(X) / val.get(Y);
            }
            return res;
        }
        
        private String find(String C) {
            String p = parents.get(C);
            while (!p.equals(parents.get(p))) {
                p = parents.get(p);
            }
            String tmp = "";
            String rC = parents.get(C);
            while (!rC.equals(parents.get(rC))) {
                tmp = parents.get(rC);
                parents.put(rC, p);
                rC = tmp;
            }
            return p;
        }
        private void union(String A, String B) {
            String rA = find(A);
            String rB = find(B);
            if (!rA.equals(rB)) {
                parents.put(rB, rA);
            }
        }
    }
  • 相关阅读:
    [POJ 1050]To the Max
    P1678 烦恼的高考志愿
    P1873 砍树
    P1102 A-B 数对
    P6771 [USACO05MAR]Space Elevator 太空电梯
    P2347 砝码称重
    P1832 A+B Problem(再升级)
    P1679 神奇的四次方数
    P1877 [HAOI2012]音量调节
    P1049 装箱问题
  • 原文地址:https://www.cnblogs.com/fatttcat/p/10016787.html
Copyright © 2011-2022 走看看