399. Evaluate Division
问题描述:
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.
解题思路:
给出已知算式{E1, E2.......En},通过使用已知算式进行运算得到问题算式{Q1, Q2........Qk}的结果,若无法通过当前算式得到结果则返回-1.0
可以将已知算式 {Ek | k belongs to 1....n} 构建成图,操作数作为顶点,结果作为边的权重。
由于可能会出现a/b和b/a两种情况,我们使用有向图来表示算式,边从被除数指向除数:
即 若 算式为 a/b = 2.0
可有图 a-----2.0----->b
我们使用邻接矩阵来表示有向图。
对于操作数:并不能确定会有什么操作数出现,而我们又需要构建邻接矩阵,所以我们需要一个索引映射(idxMap),将操作符映射到唯一一个索引。
在得到idxMap后我们可以构建图:
对每一个算式 a/b = 2.0, 需要更新 graph[a][a] = 1.0, graph[b][b] = 1.0, graph[a][b] = 2.0, graph[b][a] = 1.0/2.0
得到图后,我们从所求算式的被除数开始进行dfs。
注意需要visited来保证不出现环(即重复检测)
代码:
class Solution { public: vector<double> calcEquation(vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries) { vector<double> res; if(queries.empty()) return res; //if equations is empty if(equations.empty()){ for(int i = 0; i < queries.size(); i++){ res.push_back(-1.0); } return res; } //init graph unordered_map<string, int> idxMap; //init the index mapping for(auto e : equations){ if(idxMap.count(e.first) == 0) idxMap[e.first] = idxMap.size(); if(idxMap.count(e.second) == 0) idxMap[e.second] = idxMap.size(); } std::cout<<idxMap.size()<<std::endl; //init the graph vector<vector<double>> g(idxMap.size(), vector<double>(idxMap.size(), -1.0)); for(int i = 0; i < equations.size(); i++){ int dividend = idxMap[equations[i].first]; int divisor = idxMap[equations[i].second]; g[dividend][divisor] = values[i]; g[dividend][dividend] = 1.0; g[divisor][divisor] = 1.0; g[divisor][dividend] = 1.0/values[i]; } for(auto q : queries){ res.push_back(calculateQuery(q, g, idxMap)); } return res; } private: double dfs(vector<vector<double>> &graph, vector<bool> &visited, int idx, int targetIdx){ for(int i = 0; i < visited.size(); i++){ if(i == idx) { visited[i] = true; continue; } if(graph[idx][i] != -1.0){ if(i == targetIdx){ return graph[idx][targetIdx]; } if(!visited[i]){ visited[i] == true; double res = dfs(graph, visited, i, targetIdx); if(res != -1){ return graph[idx][i] * res; } } } } return -1.0; } double calculateQuery(pair<string, string> &q, vector<vector<double>> &graph, unordered_map<string, int> &idxMap){ int idx, targetIdx; if(idxMap.count(q.first) == 0) return -1.0; else idx = idxMap[q.first]; if(idxMap.count(q.second) == 0) return -1.0; else targetIdx = idxMap[q.second]; if(q.first == q.second) return 1.0; vector<bool> visited(idxMap.size(), false); return dfs(graph, visited, idx, targetIdx); } };