You are given an array of variable pairs equations
and an array of real numbers values
, where equations[i] = [Ai, Bi]
and values[i]
represent the equation Ai / Bi = values[i]
. Each Ai
or Bi
is a string that represents a single variable.
You are also given some queries
, where queries[j] = [Cj, Dj]
represents the jth
query where you must find the answer for Cj / Dj = ?
.
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]
Constraints:
1 <= equations.length <= 20
equations[i].length == 2
1 <= Ai.length, Bi.length <= 5
values.length == equations.length
0.0 < values[i] <= 20.0
1 <= queries.length <= 20
queries[i].length == 2
1 <= Cj.length, Dj.length <= 5
Ai, Bi, Cj, Dj
consist of lower case English letters and digits.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We're given equations like a/b = 2.0 and we need to figure out the value of other divisions, like c/a. The brute force method involves trying to find a path between the two variables in the question, by exploring all possible combinations of equations we're given.
Here's how the algorithm would work step-by-step:
def evaluate_division_brute_force(equations, values, queries):
graph = {}
for (numerator, denominator), value in zip(equations, values):
if numerator not in graph:
graph[numerator] = []
if denominator not in graph:
graph[denominator] = []
graph[numerator].append((denominator, value))
graph[denominator].append((numerator, 1.0 / value))
def find_path(start_node, end_node, visited):
# If we are looking for a node that does not exist.
if start_node not in graph or end_node not in graph:
return -1.0
if start_node == end_node:
return 1.0
visited.add(start_node)
for neighbor, value in graph[start_node]:
if neighbor not in visited:
result = find_path(neighbor, end_node, visited)
# If the path exists, return its value
if result != -1.0:
return value * result
return -1.0
results = []
for numerator, denominator in queries:
# Use a set to keep track of visited nodes to prevent loops
visited_nodes = set()
result = find_path(numerator, denominator, visited_nodes)
results.append(result)
return results
This problem is about figuring out relationships between things when you're only given some direct connections. We represent the connections as a kind of map and then efficiently explore that map to answer questions about how different things relate to each other.
Here's how the algorithm would work step-by-step:
def evaluate_division(equations, values, queries):
graph = {}
# Build the graph representing the relationships.
for (numerator, denominator), value in zip(equations, values):
if numerator not in graph:
graph[numerator] = {}
if denominator not in graph:
graph[denominator] = {}
graph[numerator][denominator] = value
graph[denominator][numerator] = 1.0 / value
def dfs(start_node, end_node, visited):
if start_node not in graph or end_node not in graph:
return -1.0
if start_node == end_node:
return 1.0
visited.add(start_node)
# Explore paths from start_node to find end_node.
for neighbor, value in graph[start_node].items():
if neighbor not in visited:
result = dfs(neighbor, end_node, visited)
if result != -1.0:
return value * result
return -1.0
results = []
for numerator, denominator in queries:
# Use DFS to find the path and calculate the result.
visited_nodes = set()
result = dfs(numerator, denominator, visited_nodes)
results.append(result)
return results
Case | How to Handle |
---|---|
Empty equations list | Return a list of -1.0 for each query, as no relationships are defined. |
Empty queries list | Return an empty list, as there are no queries to process. |
Equation with division by zero (e.g., A / B = 0) | Treat the result of the equation as 0.0 if the value is explicity given or return -1.0 if encountered during evaluation. |
Query with undefined variables (variables not in equations) | Return -1.0 for such queries, as no path can be established. |
Query with a variable dividing itself (e.g., A / A) | Return 1.0 for such queries if the variable exists in the equations. |
Cyclic equations leading to infinite recursion during evaluation | Use a visited set during graph traversal (DFS or BFS) to prevent revisiting nodes and infinite loops. |
Very large number of equations and queries, leading to potential memory issues | Consider optimizing graph representation (e.g., adjacency list instead of matrix) and using iterative BFS instead of recursive DFS to reduce memory footprint. |
Floating-point precision issues leading to incorrect comparisons | Use a small tolerance (epsilon) when comparing floating-point numbers for equality (e.g., Math.abs(result - expected) < epsilon). |