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<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries , where equations.size() == values.size(), and the values are positive. This represents the equations. Return vector<double>. 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。java
假如咱们将除数和被除数看作是图的顶点,将除数和被除数之间的倍数关系试作两者之间边的权重。即a/b=2.0
表明点a指向点b的边的权重为2.0,而点b指向点a的边的全中为1/2.0=0.5。lua
所以咱们能够将输入的表达式转化为一个加权有向图,而题目的问题则被转化为求两个点之间是否可以找到一条边,若是没法找到,则返回-1,不然返回路径上每条边的权重的乘积。code
代码以下:orm
public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) { //图的链式表示法 Map<String, List<String>> pairs = new HashMap<>(); //图上每条边的权重 Map<String, List<Double>> valuedPairs = new HashMap<>(); for(int i = 0 ; i < equations.size() ; i++) { //获取第i个方程式 List<String> 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<queries.size() ; i++) { //在图中,以被除数做为顶点,深度优先遍历图,直到找到值为除数的顶点 result[i] = dfs(queries.get(i).get(0), queries.get(i).get(1), pairs, valuedPairs, new HashSet<>(), 1.0); result[i] = result[i]==0.0 ? -1.0 : result[i]; } return result; } public double dfs(String multiplied, String multiplier, Map<String, List<String>> pairs, Map<String, List<Double>> valuedPairs, Set<String> 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<String> multipliers = pairs.get(multiplied); //得到全部邻接边的权重 List<Double> multiplierValues = valuedPairs.get(multiplied); double tmp = 0.0; for(int i = 0 ; i<multipliers.size() ; i++) { //以邻接点为新的顶点,继续深度优先遍历 //此时调用方法中curResult的值表明的是该原邻接点除以邻接点的值 //如 a/b=2, b/c=3, 则a=2b,所以当咱们以b做为邻接点寻找c时,须要记录原被除数是现被除数的两倍 tmp = dfs(multipliers.get(i), multiplier, pairs, valuedPairs, visited, curResult * multiplierValues.get(i)); //找到非零路径,结束深度优先遍历 if(tmp != 0.0){ break; } } visited.remove(multiplied); return tmp; }