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.
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 ]`
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.
For original task refer to leetcode
Approach
- Divisions are represented in a Graph form.
A / B
means we have graph that starts from node A and goes to node B - From mathematics we can derive reverse equations. Means
B / A
will be equal to1 / ( A / B)
, and graph starts from node B and goes to node A - By following two presumption above we can create a tree (look for implementation at createTree() method)
- After creating a tree we just have to traverse the tree by given parameters.
- query contains starting and ending node names.
- traversing the graph performed using DFS recursive algorithm (check traverse() method)
- visitMap is used to track already visited nodes
Time Complexity: O(V + E), where V is the number of varibles (like A,B,C …) and E is the number of equations
Space Complexity: O(V), we need additional visitMap with the maximum size V
Solution (Java)
class Solution {
class Tree {
String name;
List<Tree> child;
List<Double> cost;
Tree(String name) {
this.name = name;
this.child = new ArrayList<>();
this.cost = new ArrayList<>();
}
}
public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
Map<String, Boolean> visitMap = new HashMap<>();
Map<String, Tree> mainTree = createTree(equations, values, visitMap);
double[] resPath = new double[queries.size()];
for (int i = 0; i < queries.size(); i++) {
resPath[i] = traverse(queries.get(i).get(0), queries.get(i).get(1), mainTree, visitMap);
}
return resPath;
}
private double traverse(String x, String y, Map<String, Tree> mainTree, Map<String, Boolean> visitMap) {
if (!mainTree.containsKey(x) || !mainTree.containsKey(y)) {
return -1.0;
}
if (x.equals(y)) return 1.0;
Tree treeX = mainTree.get(x);
visitMap.put(x, true);
double pathCost = -1.0;
for (int i = 0; i < treeX.child.size(); i++) {
Tree nextX = treeX.child.get(i);
if (visitMap.get(nextX.name) == false) {
pathCost = traverse(nextX.name, y, mainTree, visitMap);
if (pathCost != -1.0) {
pathCost *= treeX.cost.get(i);
break;
}
}
}
visitMap.put(x, false);
return pathCost;
}
private Map<String, Tree> createTree(List<List<String>> equations, double[] values, Map<String, Boolean> visitMap) {
Map<String, Tree> mainTree = new HashMap<>();
for (int i = 0; i < equations.size(); i++) {
List<String> equ = equations.get(i);
double divRes = values[i];
Tree treeA = mainTree.getOrDefault(equ.get(0), new Tree(equ.get(0)));
Tree treeB = mainTree.getOrDefault(equ.get(1), new Tree(equ.get(1)));
treeA.child.add(treeB);
treeA.cost.add(divRes);
treeB.child.add(treeA);
treeB.cost.add(1.0 / divRes);
mainTree.put(equ.get(0), treeA);
mainTree.put(equ.get(1), treeB);
visitMap.putIfAbsent(equ.get(0), false);
visitMap.putIfAbsent(equ.get(1), false);
}
return mainTree;
}
}