题目要求
Equations are given in the format A / B = k, where A and B are variables represented as strings, and k is a real number (floating point number). Given some queries, return the answers. If the answer does not exist, return -1.0.
Example:
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 ].
The input is: vector> equations, vector& values, vector> queries , where equations.size() == values.size(), and the values are positive. This represents the equations. Return vector.
According to the example above:
equations = [ ["a", "b"], ["b", "c"] ],
values = [2.0, 3.0],
queries = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ].
The input is always valid. You may assume that evaluating the queries will result in no division by zero and there is no contradiction.
已知一些字母之间的关系式,问是否能够计算出其它字母之间的倍数关系?
如已知a/b=2.0 b/c=3.0
问是否能够计算出a/c, b/a, a/e, a/a, x/x
的值。如果无法计算得出,则返回-1。这里x/x
的值因为在条件中无法获知x是否等于零,因此也无法计算其真实结果,也需要返回-1。
思路和代码
假如我们将除数和被除数看做是图的顶点,将除数和被除数之间的倍数关系试做二者之间边的权重。即a/b=2.0
代表点a指向点b的边的权重为2.0,而点b指向点a的边的全中为1/2.0=0.5。
因此我们可以将输入的表达式转化为一个加权有向图,而题目的问题则被转化为求两个点之间是否能够找到一条边,如果无法找到,则返回-1,否则返回路径上每条边的权重的乘积。
代码如下:
public double[] calcEquation(List> equations, double[] values, List> queries) {
//图的链式表示法
Map> pairs = new HashMap<>();
//图上每条边的权重
Map> valuedPairs = new HashMap<>();
for(int i = 0 ; i < equations.size() ; i++) {
//获取第i个方程式
List equation = equations.get(i);
String multiplied = equation.get(0);//被除数
String multiplier = equation.get(1);//除数
//如果被除数从来没有添加到图中,则将其作为顶点在图中初始化
if(!pairs.containsKey(multiplied)) {
pairs.put(multiplied, new ArrayList<>());
valuedPairs.put(multiplied, new ArrayList<>());
}
//如果除数从来没有添加到图中,则将其作为顶点在图中初始化
if(!pairs.containsKey(multiplier)) {
pairs.put(multiplier, new ArrayList<>());
valuedPairs.put(multiplier, new ArrayList<>());
}
//添加边和边的权重
pairs.get(multiplied).add(multiplier);
pairs.get(multiplier).add(multiplied);
valuedPairs.get(multiplied).add(values[i]);
valuedPairs.get(multiplier).add(1.0 / values[i]);
}
//结果集
double[] result = new double[queries.size()];
for(int i = 0 ; i(), 1.0);
result[i] = result[i]==0.0 ? -1.0 : result[i];
}
return result;
}
public double dfs(String multiplied, String multiplier, Map> pairs, Map> valuedPairs, Set visited, double curResult) {
//如果图中不包含该被除数顶点,则无法获知该表达式的值
if(!pairs.containsKey(multiplied)) return 0.0;
//如果再次访问过该被除数,说明找到了一条环路,则该深度优先遍历结果失败,直接抛弃
if(visited.contains(multiplied)) return 0.0;
//如果被除数等于除数,则返回1.0
if(multiplied.equals(multiplier)) return curResult;
visited.add(multiplied);
//获得当前被除数的所有邻接顶点
List multipliers = pairs.get(multiplied);
//获得所有邻接边的权重
List multiplierValues = valuedPairs.get(multiplied);
double tmp = 0.0;
for(int i = 0 ; i