**给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。
另有一些以数组 queries 表示的问题,其中 queries[j] = [Cj, Dj] 表示第 j 个问题,请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。
返回 所有问题的答案 。如果存在某个无法确定的答案,则用 -1.0 替代这个答案。
注意:输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/evaluate-division
**
示例
输入:equations = [[“a”,“b”],[“b”,“c”]], values = [2.0,3.0], queries = [[“a”,“c”],[“b”,“a”],[“a”,“e”],[“a”,“a”],[“x”,“x”]]
输出:[6.00000,0.50000,-1.00000,1.00000,-1.00000]
解释:
条件:a / b = 2.0, b / c = 3.0
问题:a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ?
结果:[6.0, 0.5, -1.0, 1.0, -1.0 ]
class Solution:
def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]:
graph_dic=collections.defaultdict(dict) # 防止出现keyError 默认值是dict
for [divis, divid], value in zip(equations, values):
graph_dic[divis][divid] = value # 嵌套字典
graph_dic[divid][divis] = 1.0/value
def Dfs(graph_dic, visit, i, j):
if j in graph_dic[i]: return graph_dic[i][j] # 证明i能直接到达j
# j是间接邻接与i i无法一步到达j 则需要通过D与i邻接的结点找到j
# 这里不用注意j是否能间接邻接与i 访问到所有i邻接的结点就可以判断j是否能邻接与i
# 接下来就是要遍历i邻接的结点 再递归调用Dfs
for child in graph_dic[i]:
if child not in visit: # 结点未被访问到
visit.add(child)
ret = Dfs(graph_dic, visit, child, j) # 递归 现在是child到j 而不是i到j
if ret != -1:
return graph_dic[i][child]*ret # 乘上i到child的权值
return -1 # 证明i的child里面 没有一个是邻接与j的
ans = []
# 枚举所有路径组合
for i, j in queries:
if i not in graph_dic or j not in graph_dic:
ans.append(-1.0)
elif i == j:
ans.append(1.0)
else:
ans.append(Dfs(graph_dic, set(), i, j))
return ans
# 并查集
# 首先初始化一个字典 包含所有除数与被除数
div = {}
for divis, divid in equations:
div[divis] = [divis, 1] # 代表初始化时 每个结点父亲都是自己 权值为1
div[divid] = [divid, 1]
# find 路径压缩 一层一层往上寻找根结点
def find(i):
if i != div[i][0]: # 非根结点
origin = div[i][0] # 记录下上一层结点 更新权值
div[i][0] = find(div[i][0]) # 递归查询上一层结点
div[i][1] *= div[origin][1]
# a --(3.0)> b --(2.0)>c 一层一层往上找 则 a --(rank)>c rank=3.0*2.0
return div[i][0]
# union
def union(i, j, val):
parentOfi = find(i)
parentOfj = find(j)
if parentOfi != parentOfj:
div[parentOfj][0] = parentOfi
div[parentOfj][1] = div[i][1]*val/div[j][1]
for [i, j], val in zip(equations, values):
union(i, j, val)
ans = []
for i, j in queries:
if i not in div or j not in div:
ans.append(-1.0)
else:
if i == j:
ans.append(1.0)
elif find(i) == find(j):
ans.append(div[j][1]/div[i][1])
else:
ans.append(-1.0)
return ans
Java
DFS
class Solution {
HashMap<String, HashMap<String, Double>> graph;
public double dfs(String i, String j, HashSet visit){
if (graph.get(i).containsKey(j)) return graph.get(i).get(j);
visit.add(i);
for (String child : graph.get(i).keySet()){
if (!visit.contains(child)){
visit.add(child);
double rev = dfs(child, j, visit);
if (rev != -1){
rev *= graph.get(i).get(child);
return rev;
}
}
}
return -1.0;
}
public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
graph = new HashMap<>();
int size = values.length;
for (int i = 0; i < size; i++){
graph.put(equations.get(i).get(0), new HashMap<>());
graph.put(equations.get(i).get(1), new HashMap<>());
}
for (int i = 0; i < size; i++){
graph.get(equations.get(i).get(0)).put(equations.get(i).get(1), values[i]);
graph.get(equations.get(i).get(1)).put(equations.get(i).get(0), 1/values[i]);
}
double[] ans = new double[queries.size()];
for (int k = 0; k < queries.size(); k++){
String i = queries.get(k).get(0);
String j = queries.get(k).get(1);
if (!graph.containsKey(i) || !graph.containsKey(j)){
ans[k] = -1.0;
}
else{
if (i.equals(j)) ans[k] = 1.0;
else{
ans[k] = dfs(i, j, new HashSet<>());
}
}
}
return ans;
}
}
并查集
class Solution {
class Node{
String parent;
double weight;
public Node(String i, double j){
this.parent = i;
this.weight = j;
}
}
class UnionFind{
HashMap<String, Node> f;
public UnionFind(List<List<String>> equations){
f = new HashMap<>();
for (int i = 0; i < equations.size(); i++){
String u = equations.get(i).get(0), v = equations.get(i).get(1);
f.put(u, new Node(u, 1.0));
f.put(v, new Node(v, 1.0));
}
}
public String find(String x){
if (x != f.get(x).parent){
String origian = f.get(x).parent; // 记录下x的上一层节点
f.get(x).parent = find(f.get(x).parent);
f.get(x).weight *= f.get(origian).weight;
}
return f.get(x).parent; // 一定要return f.get(x).parent;
}
public void union(String i, String j, double val){
String ri = find(i), rj = find(j);
if (!ri.equals(rj)){
f.get(rj).parent = ri;
f.get(rj).weight = val*f.get(i).weight/f.get(j).weight;
}
}
public boolean isConnect(String i, String j){
return find(i).equals(find(j));
}
}
public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
int size = values.length;
UnionFind un = new UnionFind(equations);
double[] ans = new double[queries.size()];
for (int i = 0; i < size; i++){
un.union(equations.get(i).get(0), equations.get(i).get(1), values[i]);
}
for (int i = 0; i < queries.size(); i++){
String u = queries.get(i).get(0), v = queries.get(i).get(1);
if (!un.f.containsKey(u) || !un.f.containsKey(v)){
ans[i] = -1.0;
}
else{
if (u.equals(v)) ans[i] = 1.0;
else if (un.isConnect(u, v)) ans[i] = un.f.get(v).weight / un.f.get(u).weight;
else ans[i] = -1.0;
}
}
return ans;
}
}