这道题目的解法是带权值的并查集。
并查集
可以看这篇文章的讲解:
https://blog.csdn.net/niushuai666/article/details/6662911
并查集由一个整数型的数组和两个函数构成。数组pre[]记录了每个点的前导点是什么,函数find是查找,join是合并
解题思路:建立两个map,一个map存储上一级结点。一个map存储比值。首先不断构建查并集结构。如果两者根节点不一致,进行合并。然后输出最终的结果即可。
public class Solution {
HashMap<String, String> path = new HashMap<>(); // key是当前结点,value是父结点
HashMap<String, Double> value = new HashMap<>(); // key是当前结点,value是父结点/此结点
public double[] calcEquation(List<List<String>> equations,
double[] values,
List<List<String>> queries) {
// 这道题目用并查集的方式来求解。
// 带权值的并查集。
for (int i = 0; i < values.length; i++) {// 遍历被除数,除数,商。
String parent = equations.get(i).get(0);
String child = equations.get(i).get(1);
double divide = values[i];
// 首先保证 map中有这两个结点。
if (!path.containsKey(parent)) {
path.put(parent, parent);
value.put(parent, 1.0);
}
if (!path.containsKey(child)) {
path.put(child, child);
value.put(child, 1.0);
}
String root1 = findRoot(parent);// 找到了parent的根节点
String root2 = findRoot(child);// 找到了,child的根节点
// 分成两种情况,两者根节点一致;两者根节点不一致。
// 一致的话,不用管了。不一致的话,进行根节点的合并。
if(!root1.equals(root2)){
path.put(root2,root1);
value.put(root2,divide*value.get(parent)/value.get(child));
}
}
// 现在已经将数据按照并查集的格式存储好了
double[] res = new double[queries.size()];
for (int i = 0; i< queries.size(); i++) {
List<String> query = queries.get(i);
String s1 = query.get(0);
String s2 = query.get(1);
if(!(path.containsKey(s1)&&path.containsKey(s2))){
res[i] = -1.0;
continue;
}
// 说明 两者都包括
String root1 = findRoot(s1);
String root2 = findRoot(s2);
if(!root1.equals(root2)){
res[i] = -1.0;
continue;
}
// 说明 两者的根结点一致。
res[i] = value.get(s2)/value.get(s1);
}
return res;
}
private String findRoot(String str) {
// 这个方法能够找到,str的根结点。
// 并且最终将此结点直接与根节点相连。(设置其value值)
String save = str;
double divide = 1.0;
if (path.get(str).equals(str)) {
return str;
}
// 说明root不是自己。
while (!path.get(str).equals(str)) {
// 如果str的父结点 不等于 str
divide *= value.get(str);
str = path.get(str);
}
divide *= value.get(str);
path.put(save, str);
value.put(save, divide);
return str;
}
}