Evaluate Division - BFS

AbhiAbhi
4 min read

You are given an array of variable pairs equations and an array of real numbers values, where equations[i] = [A<sub>i</sub>, B<sub>i</sub>] and values[i] represent the equation A<sub>i</sub> / B<sub>i</sub> = values[i]. Each A<sub>i</sub> or B<sub>i</sub> is a string that represents a single variable.

You are also given some queries, where queries[j] = [C<sub>j</sub>, D<sub>j</sub>] represents the j<sup>th</sup> query where you must find the answer for C<sub>j</sub> / D<sub>j</sub> = ?.

Return the answers to all queries. If a single answer cannot be determined, return -1.0.

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

Note: The variables that do not occur in the list of equations are undefined, so the answer cannot be determined for them.

Example 1:

Input: equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
Output: [6.00000,0.50000,-1.00000,1.00000,-1.00000]
Explanation: 
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 ]
note: x is undefined => -1.0

Example 2:

Input: equations = [["a","b"],["b","c"],["bc","cd"]], values = [1.5,2.5,5.0], queries = [["a","c"],["c","b"],["bc","cd"],["cd","bc"]]
Output: [3.75000,0.40000,5.00000,0.20000]

Example 3:

Input: equations = [["a","b"]], values = [0.5], queries = [["a","b"],["b","a"],["a","c"],["x","y"]]
Output: [0.50000,2.00000,-1.00000,-1.00000]

1) Explain the problem

The problem is to evaluate division queries based on given equations and values. Each equation represents a relationship between two variables, and we need to compute the result of the division for a set of queries. If a result cannot be determined, return -1.0.

2) Short easy to remember solution/approach

  • Use a graph to represent the relationships between variables.

  • Use Breadth-First Search (BFS) to evaluate the division queries by traversing the graph.

3) Solution in JavaScript with code commenting

function calcEquation(equations, values, queries) {
    const graph = {};

    // Build the graph
    equations.forEach(([A, B], index) => {
        if (!graph[A]) graph[A] = {};
        if (!graph[B]) graph[B] = {};
        graph[A][B] = values[index];
        graph[B][A] = 1 / values[index];
    });

    // BFS function to find the value of division
    const bfs = (start, end) => {
        if (!(start in graph) || !(end in graph)) return -1.0;
        if (start === end) return 1.0;

        const queue = [[start, 1.0]];
        const visited = new Set();

        while (queue.length > 0) {
            const [current, product] = queue.shift();
            if (current === end) return product;

            visited.add(current);

            for (const neighbor in graph[current]) {
                if (!visited.has(neighbor)) {
                    queue.push([neighbor, product * graph[current][neighbor]]);
                }
            }
        }

        return -1.0;
    };

    // Evaluate each query
    return queries.map(([C, D]) => bfs(C, D));
}

4) Explanation of the solution in an easy-to-understand way with a real-life example

Imagine you have a network of currency exchange rates. For example, if 1 USD is equal to 0.85 EUR and 1 EUR is equal to 0.75 GBP, and you want to find out how many GBP you can get for 1 USD, you multiply the exchange rates. This is similar to our problem, where we use a graph to represent the relationships and BFS to find the shortest path between the currencies.

5) Code explanation in pointers

  • Graph Initialization: Build a graph where each node represents a variable, and each edge represents the division value between variables.

  • BFS Function:

    • Base Case: If either the start or end variable is not in the graph, return -1.0.

    • Self-Division Case: If the start and end variables are the same, return 1.0.

    • Queue Initialization: Use a queue to manage the BFS traversal, starting with the start variable and an initial product of 1.0.

    • Visited Set: Keep track of visited nodes to avoid cycles.

    • Graph Traversal: While the queue is not empty, dequeue the front element and check if it matches the end variable. If it does, return the product. Otherwise, enqueue all unvisited neighbors with the updated product.

  • Query Evaluation: For each query, use BFS to find the result.

6) Complexities

  • Time Complexity: O(Q * (V + E)) where Q is the number of queries, V is the number of variables, and E is the number of edges. Each BFS traversal explores the graph.

  • Space Complexity: O(V + E) for storing the graph and visited set.

Using BFS, we ensure a level-by-level traversal to find the shortest path in terms of the number of edges, which helps in efficiently computing the division results.

0
Subscribe to my newsletter

Read articles from Abhi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Abhi
Abhi