[LeetCode] 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.
给一些有结果的除法等式,又给了一些除法式子要查询结果,根据已知除法等式求结果,没有答案的返回-1。
解法1:Graph,Image a/b = k as a link between node a and b, the weight from a to b is k, the reverse link is 1/k. Query is to find a path between two nodes.
解法2:Union Find
解法3:Hash + DFS
Java: Graph
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | public double [] calcEquation(String[][] equations, double [] values, String[][] queries) { HashMap<String, ArrayList<String>> pairs = new HashMap<String, ArrayList<String>>(); HashMap<String, ArrayList<Double>> valuesPair = new HashMap<String, ArrayList<Double>>(); for ( int i = 0 ; i < equations.length; i++) { String[] equation = equations[i]; if (!pairs.containsKey(equation[ 0 ])) { pairs.put(equation[ 0 ], new ArrayList<String>()); valuesPair.put(equation[ 0 ], new ArrayList<Double>()); } if (!pairs.containsKey(equation[ 1 ])) { pairs.put(equation[ 1 ], new ArrayList<String>()); valuesPair.put(equation[ 1 ], new ArrayList<Double>()); } pairs.get(equation[ 0 ]).add(equation[ 1 ]); pairs.get(equation[ 1 ]).add(equation[ 0 ]); valuesPair.get(equation[ 0 ]).add(values[i]); valuesPair.get(equation[ 1 ]).add( 1 /values[i]); } double [] result = new double [queries.length]; for ( int i = 0 ; i < queries.length; i++) { String[] query = queries[i]; result[i] = dfs(query[ 0 ], query[ 1 ], pairs, valuesPair, new HashSet<String>(), 1.0 ); if (result[i] == 0.0 ) result[i] = - 1.0 ; } return result; } private double dfs(String start, String end, HashMap<String, ArrayList<String>> pairs, HashMap<String, ArrayList<Double>> values, HashSet<String> set, double value) { if (set.contains(start)) return 0.0 ; if (!pairs.containsKey(start)) return 0.0 ; if (start.equals(end)) return value; set.add(start); ArrayList<String> strList = pairs.get(start); ArrayList<Double> valueList = values.get(start); double tmp = 0.0 ; for ( int i = 0 ; i < strList.size(); i++) { tmp = dfs(strList.get(i), end, pairs, values, set, value*valueList.get(i)); if (tmp != 0.0 ) { break ; } } set.remove(start); return tmp; } |
Java: Union Find
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class Solution { class Node{ String label; double val; public Node(String label, double val){ this .label=label; this .val=val;} } public double [] calcEquation(String[][] equations, double [] values, String[][] queries) { Map<String, Node> map= new HashMap<>(); for ( int i= 0 ; i<equations.length; i++){ String n= equations[i][ 0 ], d= equations[i][ 1 ]; Node N= find(map, n), D= find(map, d); if (!N.label.equals(D.label)) map.put(N.label, new Node(D.label, values[i]*D.val/N.val)); } double [] res= new double [queries.length]; for ( int i= 0 ; i<res.length; i++){ res[i]=- 1.0 ; String n=queries[i][ 0 ], d=queries[i][ 1 ]; if (!map.containsKey(n) || !map.containsKey(d)) continue ; Node N= find(map, n), D= find(map, d); if (!N.label.equals(D.label)) continue ; res[i]=N.val/D.val; } return res; } public Node find(Map<String, Node> map, String cur){ if (!map.containsKey(cur)) map.put(cur, new Node(cur, 1.0 )); Node curNode= map.get(cur); double val= 1.0 ; while (!map.get(cur).label.equals(cur)){ val*=map.get(cur).val; cur=map.get(cur).label; } curNode.label=cur; curNode.val=val; return curNode; } } |
Java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | public double [] calcEquation(String[][] equations, double [] values, String[][] query) { double [] result = new double [query.length]; // filter unexpected words // 过滤掉没有遇见过的字符 Set<String> words = new HashSet<>(); for (String[] strs : equations) { words.add(strs[ 0 ]); words.add(strs[ 1 ]); } for ( int i = 0 ; i < query.length; ++i) { String[] keys = query[i]; if (!words.contains(keys[ 0 ]) || !words.contains(keys[ 1 ])) result[i] = - 1 .0d; else { Stack<Integer> stack = new Stack<>(); result[i] = helper(equations, values, keys, stack); } } return result; } public double helper(String[][] equations, double [] values, String[] keys, Stack<Integer> stack) { // 直接查找,key的顺序有正反 // look up equations directly for ( int i = 0 ; i < equations.length; ++i) { if (equations[i][ 0 ].equals(keys[ 0 ]) && equations[i][ 1 ].equals(keys[ 1 ])) return values[i]; if (equations[i][ 0 ].equals(keys[ 1 ]) && equations[i][ 1 ].equals(keys[ 0 ])) return 1 / values[i]; } // lookup equations by other equations // 间接查找,key的顺序也有正反 for ( int i = 0 ; i < equations.length; ++i) { if (!stack.contains(i) && keys[ 0 ].equals(equations[i][ 0 ])) { stack.push(i); double temp = values[i] * helper(equations, values, new String[]{equations[i][ 1 ], keys[ 1 ]}, stack); if (temp > 0 ) return temp; else stack.pop(); } if (!stack.contains(i) && keys[ 0 ].equals(equations[i][ 1 ])) { stack.push(i); double temp = helper(equations, values, new String[]{equations[i][ 0 ], keys[ 1 ]}, stack) / values[i]; if (temp > 0 ) return temp; else stack.pop(); } } // 查不到,返回-1 return - 1 .0d; } |
Java: Union find
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | public double [] calcEquation(String[][] equations, double [] values, String[][] query) { // map string to integer Map<String, Integer> mIdTable = new HashMap<>(); int len = 0 ; for (String[] words : equations) for (String word : words) if (!mIdTable.containsKey(word)) mIdTable.put(word, len++); // init parent index and value Node[] nodes = new Node[len]; for ( int i = 0 ; i < len; ++i) nodes[i] = new Node(i); // union, you can take an example as follows // (a/b=3)->(c/d=6)->(b/d=12) for ( int i = 0 ; i < equations.length; ++i) { String[] keys = equations[i]; int k1 = mIdTable.get(keys[ 0 ]); int k2 = mIdTable.get(keys[ 1 ]); int groupHead1 = find(nodes, k1); int groupHead2 = find(nodes, k2); nodes[groupHead2].parent = groupHead1; nodes[groupHead2].value = nodes[k1].value * values[i] / nodes[k2].value; } // query now double [] result = new double [query.length]; for ( int i = 0 ; i < query.length; ++i) { Integer k1 = mIdTable.get(query[i][ 0 ]); Integer k2 = mIdTable.get(query[i][ 1 ]); if (k1 == null || k2 == null ) result[i] = -1d; else { int groupHead1 = find(nodes, k1); int groupHead2 = find(nodes, k2); if (groupHead1 != groupHead2) result[i] = -1d; else result[i] = nodes[k2].value / nodes[k1].value; } } return result; } public int find(Node[] nodes, int k) { int p = k; while (nodes[p].parent != p) { p = nodes[p].parent; // compress nodes[k].value *= nodes[p].value; } // compress nodes[k].parent = p; return p; } private static class Node { int parent; double value; public Node( int index) { this .parent = index; this .value = 1d; } } |
Python: Union Find
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | class Solution: def calcEquation( self , equations, values, queries): """ :type equations: List[List[str]] :type values: List[float] :type queries: List[List[str]] :rtype: List[float] """ res = [] parent = {} # i.e. [a, b] then parent[a] = b weight = {} # i.e. a / b = 2.0, then weight[a] = 2.0 ufind = UnionFind(parent, weight) for i, edge in enumerate (equations): x1, x2 = edge[ 0 ], edge[ 1 ] val = values[i] if x1 not in parent and x2 not in parent: parent[x1] = x2 parent[x2] = x2 weight[x1] = val weight[x2] = 1 elif x1 not in parent: parent[x1] = x2 weight[x1] = val elif x2 not in parent: # weight[x1] already exists, if make x2 be x1's parent. then weight[x1] will be overwrite. parent[x2] = x1 weight[x2] = 1 / val else : ufind.union(x1, x2, val) for x1, x2 in queries: if x1 not in parent or x2 not in parent or ufind.find(x1) ! = ufind.find(x2): res.append( - 1.0 ) else : factor1 = weight[x1] factor2 = weight[x2] res.append(factor1 / factor2) return res class UnionFind(): def __init__( self , parent, weight): self .parent = parent self .weight = weight def find( self , vertex): if self .parent[vertex] = = vertex: return vertex root = self .find( self .parent[vertex]) self .weight[vertex] * = self .weight[ self .parent[vertex]] self .parent[vertex] = root return root def union( self , vertex1, vertex2, val): root1 = self .find(vertex1) root2 = self .find(vertex2) self .weight[root1] = self .weight[vertex2] * val / self .weight[vertex1] self .parent[root1] = root2 |
Python: Union Find + Path Compression + Rank
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | def calcEquation( self , equations, values, queries): """ Time: O(E+Q) , Union is approx O(1) because it's using path compression during find. Space: O(E) """ self .parents = {} self .weights = {} # Presents it as the val point to another graph self .rank = {} for (w, v), val in zip (equations, values): if w not in self .parents: self .parents[w] = w self .weights[w] = 1.0 self .rank[w] = 1 if v not in self .parents: self .parents[v] = v self .weights[v] = 1.0 self .rank[v] = 1 self .union(w, v, val) res = [] for query in queries: w, v = query if w not in self .parents or v not in self .parents: res.append( - 1.0 ) continue p1, p2 = self .find(w), self .find(v) if p1 ! = p2: res.append( - 1.0 ) else : res.append( self .weights[w] / self .weights[v]) return res def find( self , node): if node ! = self .parents[node]: p = self .parents[node] self .parents[node] = self .find(p) self .weights[node] = self .weights[node] * self .weights[p] return self .parents[node] def union( self , u, v, val): p1 = self .find(u) p2 = self .find(v) if self .rank[p1] > self .rank[p2]: p1, p2 = p2, p1 val = 1 / val v, u = u, v if p1 ! = p2: self .parents[p1] = p2 self .rank[p2] + = self .rank[p1] self .rank[p1] = 1 self .weights[p1] = ( self .weights[v] / self .weights[u] ) * val |
C++: Union Find
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | class Solution { public : vector< double > calcEquation(vector<pair<string, string>> equations, vector< double >& values, vector<pair<string, string>> queries) { unordered_map<string, Node*> map; vector< double > res; for ( int i = 0; i < equations.size(); i ++) { string s1 = equations[i].first, s2 = equations[i].second; if (map.count(s1) == 0 && map.count(s2) == 0) { map[s1] = new Node(); map[s2] = new Node(); map[s1] -> value = values[i]; map[s2] -> value = 1; map[s1] -> parent = map[s2]; } else if (map.count(s1) == 0) { map[s1] = new Node(); map[s1] -> value = map[s2] -> value * values[i]; map[s1] -> parent = map[s2]; } else if (map.count(s2) == 0) { map[s2] = new Node(); map[s2] -> value = map[s1] -> value / values[i]; map[s2] -> parent = map[s1]; } else { unionNodes(map[s1], map[s2], values[i], map); } } for ( auto query : queries) { if (map.count(query.first) == 0 || map.count(query.second) == 0 || findParent(map[query.first]) != findParent(map[query.second])) res.push_back(-1); else res.push_back(map[query.first] -> value / map[query.second] -> value); } return res; } private : struct Node { Node* parent; double value = 0.0; Node() {parent = this ;} }; void unionNodes(Node* node1, Node* node2, double num, unordered_map<string, Node*>& map) { Node* parent1 = findParent(node1), *parent2 = findParent(node2); double ratio = node2 -> value * num / node1 -> value; for ( auto it = map.begin(); it != map.end(); it ++) if (findParent(it -> second) == parent1) it -> second -> value *= ratio; parent1 -> parent = parent2; } Node* findParent(Node* node) { if (node -> parent == node) return node; node -> parent = findParent(node -> parent); return node -> parent; } }; |
C++: Hash + DFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | class Solution { public : vector< double > calcEquation(vector<pair<string, string>> equations, vector< double >& values, vector<pair<string, string>> query) { unordered_map<string,unordered_map<string, double >> m; vector< double > res; for ( int i = 0; i < values.size(); ++i) { m[equations[i].first].insert(make_pair(equations[i].second,values[i])); if (values[i]!=0) m[equations[i].second].insert(make_pair(equations[i].first,1/values[i])); } for ( auto i : query) { unordered_set<string> s; double tmp = check(i.first,i.second,m,s); if (tmp) res.push_back(tmp); else res.push_back(-1); } return res; } double check(string up, string down, unordered_map<string,unordered_map<string, double >> &m, unordered_set<string> &s) { if (m[up].find(down) != m[up].end()) return m[up][down]; for ( auto i : m[up]) { if (s.find(i.first) == s.end()) { s.insert(i.first); double tmp = check(i.first,down,m,s); if (tmp) return i.second*tmp; } } return 0; } }; |
All LeetCode Questions List 题目汇总
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步