399. Evaluate Division - Medium

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);
        }
    }
}

 

posted @ 2018-11-25 19:17  fatttcat  阅读(100)  评论(0编辑  收藏  举报