這道題目的解法是帶權值的並查集。
並查集
可以看這篇文章的講解:
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;
}
}