Evaluate Division
Difficulty: Medium Source: NeetCode
Problem
You are given an array of variable pairs
equationsand an array of real numbersvalues, whereequations[i] = [Ai, Bi]andvalues[i]represent the equationAi / Bi = values[i]. EachAiorBiis a string that represents a single variable.You are also given some
queries, wherequeries[j] = [Cj, Dj]represents thej-th query where you must find the result ofCj / Dj.Return the results of all queries. If the answer to a query does not exist, return
-1.0.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.0, 0.5, -1.0, 1.0, -1.0]Constraints:
1 <= equations.length <= 20equations[i].length == 21 <= Ai.length, Bi.length <= 5values[i] > 0.01 <= queries.length <= 20
Prerequisites
Before attempting this problem, you should be comfortable with:
- Weighted directed graphs — edges have a value (the division result)
- BFS / DFS for path finding — multiplying weights along a path gives the query answer
- Graph modeling — translating a math problem into a graph traversal
1. BFS for Each Query
Intuition
Model the variables as nodes and the equations as directed weighted edges. If a / b = 2, add edges a → b with weight 2.0 and b → a with weight 1/2.0 = 0.5. To answer a / c, find a path from a to c and multiply all edge weights along the path. BFS is perfect for this since any path gives the correct answer (the graph is consistent).
Algorithm
- Build a weighted adjacency list from equations and values.
- For each query
(src, dst):- If either is unknown, return
-1.0. - If
src == dst, return1.0. - BFS from
src, tracking the accumulated product. Stop whendstis found.
- If either is unknown, return
- Return
-1.0ifdstis unreachable.
Solution
from collections import defaultdict, deque
def calcEquation(equations: list[list[str]], values: list[float], queries: list[list[str]]) -> list[float]:
graph = defaultdict(dict)
for (a, b), val in zip(equations, values):
graph[a][b] = val
graph[b][a] = 1.0 / val
def bfs(src, dst):
if src not in graph or dst not in graph:
return -1.0
if src == dst:
return 1.0
visited = {src}
queue = deque([(src, 1.0)])
while queue:
node, product = queue.popleft()
for neighbor, weight in graph[node].items():
if neighbor == dst:
return product * weight
if neighbor not in visited:
visited.add(neighbor)
queue.append((neighbor, product * weight))
return -1.0
return [bfs(src, dst) for src, dst in queries]
equations = [["a","b"],["b","c"]]
values = [2.0, 3.0]
queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
print(calcEquation(equations, values, queries))
# [6.0, 0.5, -1.0, 1.0, -1.0]
Complexity
- Time:
O(Q * (V + E))where Q = queries, V = unique variables, E = equations - Space:
O(V + E)for the graph
2. Floyd-Warshall on Division
Intuition
If we know a/b and b/c, we can compute a/c = (a/b) * (b/c). This is exactly the Floyd-Warshall transitive closure idea applied to multiplicative ratios. Precompute all pairwise division results using three nested loops, then answer each query in O(1).
Algorithm
- Initialize
dist[a][b] = valfor each equation,dist[a][a] = 1.0for all known variables,dist[b][a] = 1/val. - For each intermediate
k, for eachi, for eachj: ifdist[i][k]anddist[k][j]are known, setdist[i][j] = dist[i][k] * dist[k][j]. - Answer each query with
dist[src][dst]or-1.0if unknown.
Solution
from collections import defaultdict
def calcEquation(equations: list[list[str]], values: list[float], queries: list[list[str]]) -> list[float]:
# Collect all unique variables
variables = set()
for a, b in equations:
variables.add(a)
variables.add(b)
# Initialize ratio table
ratio = defaultdict(dict)
for var in variables:
ratio[var][var] = 1.0
for (a, b), val in zip(equations, values):
ratio[a][b] = val
ratio[b][a] = 1.0 / val
# Floyd-Warshall: compute transitive ratios
for k in variables:
for i in variables:
for j in variables:
if k in ratio[i] and j in ratio[k]:
ratio[i][j] = ratio[i][k] * ratio[k][j]
result = []
for src, dst in queries:
if src not in ratio or dst not in ratio[src]:
result.append(-1.0)
else:
result.append(ratio[src][dst])
return result
equations = [["a","b"],["b","c"]]
values = [2.0, 3.0]
queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
print(calcEquation(equations, values, queries))
# [6.0, 0.5, -1.0, 1.0, -1.0]
Complexity
- Time:
O(V³ + Q)— V³ for Floyd-Warshall, Q for queries - Space:
O(V²)for the ratio table
Common Pitfalls
Unknown variables in queries. If src or dst doesn’t appear in any equation, return -1.0. Check src not in graph before doing any traversal.
Self-queries. a / a = 1.0 if a is a known variable. But x / x = -1.0 if x is never mentioned in equations — it’s unknown, not 1.0.
Adding reverse edges. For each equation a / b = k, add both graph[a][b] = k and graph[b][a] = 1/k. Without reverse edges, many queries will fail even when the answer is computable.