题目描述
【leetcode】399. 除法求值( Evaluate Division )
给出方程式 A / B = k, 其中 A 和 B 均为代表字符串的变量, k 是一个浮点型数字。根据已知方程式求解问题,并返回计算结果。如果结果不存在,则返回 -1.0。
示例 :
给定 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 ]
输入为:
- vector<pair<string, string>> equations,
- vector<double>& values,
- vector<pair<string, string>> queries(方程式,方程式结果,问题方程式),
其中 equations.size() == values.size(),即方程式的长度与方程式结果长度相等(程式与结果一一对应),并且结果值均为正数。以上为方程式的描述。 返回vector<double>类型。
基于上述例子,输入如下:
equations(方程式) = [ ["a", "b"], ["b", "c"] ],
values(方程式结果) = [2.0, 3.0],
queries(问题方程式) = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ].
输入总是有效的。你可以假设除法运算中不会出现除数为0的情况,且不存在任何矛盾的结果。
第一次解答
思路
构建带权值边的并查集,对于每个方程式有两种情况
- 查询是否联通,若不联通,则答案为-1.0
- 若联通,则求出其与根相除的结果,根据结果计算方程式。
例如,对于题目示例:
- 构造并查集:a->b->c,其中a->b的边的权值为2.0,b->c的边的权值为3.0
- 以计算b/a时为例,以root结点为桥梁,计算b/a的值:
1. 首先计算b/root,这里root为c,则b/c = 3.0
2. 然后计算a/root,这里root为c,则a/c = a/b * b/c = 2.0 * 3.0 = 6.0
3. 最后计算方程式结果:b/a = 3.0/6.0 = 0.5
注意:
- 根据以上分析可知,该并查集不能进行路径压缩和rank优化等操作,并查集本身结构必须与方程式结构相同,否则计算出来的结果必定出错。
- 其实结构也可以不相同,但是结构变化时,边的指向也就改变了,必须注意更新边的权重。
test case:
[[“a”,“b”],[“b”,“c”]]
[2.0,3.0]
[[“a”,“c”],[“b”,“a”],[“a”,“e”],[“a”,“a”],[“x”,“x”]]
[[“a”,“b”],[“b”,“c”],[“bc”,“cd”]]
[1.5,2.5,5.0]
[[“a”,“c”],[“c”,“b”],[“bc”,“cd”],[“cd”,“bc”]]
代码:
class Solution {
public:
int count;
unordered_map<string, string> parents; // 存储当前结点的父母
unordered_map<string, double> weights; // 存储 当前结点值/父母值 的结果
// 返回root以及从a/root的值
pair<string ,double> MyFind(string a){
if(parents.find(a) == parents.end())
return {
"", -1.0};
double result = 1.0;
while(a != parents[a]){
result *= weights[a]; // result *= a/parent;
// 路径压缩后还需要更新weights,这里偷懒就不路径压缩了
a = parents[a];
}
return {
a, result}; // 返回a的根节点,和a/root的结果
}
// a_b表示a除以b的结果
void MyUnion(string a, string b, double a_b){
pair<string, double> p1 = MyFind(a);
pair<string, double> p2 = MyFind(b);
if("" == p1.first || "" == p2.first) return;
if(p1.first == p2.first) return;
parents[p1.first] = p2.first;
weights[p1.first] = 1/p1.second * a_b * p2.second; // 更新权重
count--;
}
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
// 并
for(int i=0; i<equations.size(); ++i){
string a = equations[i][0];
string b = equations[i][1];
// 并查集初始化
if(parents.find(a) == parents.end()){
count++;
parents[a] = a;
weights[a] = 1.0;
}
if(parents.find(b) == parents.end()){
count++;
parents[b] = b;
weights[b] = 1.0;
}
// 并操作
MyUnion(a, b, values[i]);
}
// 查
vector<double> result;
for(auto &q : queries){
string a = q[0];
string b = q[1];
pair<string, double> p1 = MyFind(a); // p1.second = a/p1
pair<string, double> p2 = MyFind(b); // p2.second = b/p2
if(p1.first != p2.first || "" == p1.first || "" == p2.first){
result.push_back(-1.0);
}
else{
result.push_back(p1.second/p2.second); // a/b = (a/p1) / (b/p2);
}
}
return result;
}
};
结果: