399. Evaluate Division

44 阅读1分钟

image.png

Solution Build graph and BFS

image.png

  • The direction of edge indicates the order of division,
  • and the weight of edge indicates the result of division.
class Solution {
    class Node {
        String var; // variable name
        double accProduct; // accumulated product to this var
        Node(String var, double accProduct) {
            this.var = var;
            this.accProduct = accProduct;
        }
    }

    public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
        // build graph
        // Key: variable name
        // Value:  【next var name, edge weight to next var (the quotient)】
        Map<String, Map<String, Double>> graph = new HashMap<>();

        for (int i = 0; i < equations.size(); i++) {
            String dividend = equations.get(i).get(0); // from
            String divisor = equations.get(i).get(1); // to
            double quotient = values[i]; // edge weight

            if (!graph.containsKey(dividend)) {
                graph.put(dividend, new HashMap<String, Double>());
            }

            if (!graph.containsKey(divisor)) {
                graph.put(divisor, new HashMap<String, Double>());
            }

            // Add forward and reverse edges with corresponding ratios
            graph.get(dividend).put(divisor, quotient);  // a/b = 2
            graph.get(divisor).put(dividend, 1 / quotient); // b/a = 0.5
        }

        double[] res = new double[queries.size()];

        // evaluate each query
        for(int i = 0; i < queries.size(); i++) {
            String start = queries.get(i).get(0);
            String end = queries.get(i).get(1);

            // CASE 1: either var not present in graph
            if (!graph.containsKey(start) || !graph.containsKey(end)) {
                res[i] = -1.0;
            } else if (start == end) {
                res[i] = 1.0; // CASE 2: a/a=1
            } else {
                res[i] = pathProduct(graph, start, end); // CASE 3: call bfs
            }
        }
        return res;
    }

    // search for a path from start to end and calculate accumulated path product
    public double pathProduct(Map<String, Map<String, Double>> graph, String start, String end) {

        Queue<Node> queue = new LinkedList<>();

        // At start node, accumulated product is 1
        queue.offer(new Node(start, 1.0));

        // visited, cant go back
        Set<String> visited = new HashSet<>();

        while(!queue.isEmpty()) {
            Node curNode = queue.poll();

            // reach target variable, return the current accumulated product
            if (curNode.var.equals(end)) { // !!!! not ==
                return curNode.accProduct;
            }

            visited.add(curNode.var);

            for (Map.Entry<String, Double> neighbour : graph.get(curNode.var).entrySet()) {
                String nextVar = neighbour.getKey();
                double pathWeight = neighbour.getValue(); // edge weight
                if (visited.contains(nextVar)) {
                    continue;
                }
                queue.offer(new Node(nextVar, pathWeight * curNode.accProduct)); //update acc product
            }
        }

        return -1.0; // no path from start to end
    }
}