题目链接
给出方程式 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 ]
基于上述例子,输入如下:
equations(方程式) = [ [“a”, “b”], [“b”, “c”] ],
values(方程式结果) = [2.0,3.0],
queries(问题方程式) = [ [“a”, “c”], [“b”, “a”], [“a”, “e”], [“a”, “a”], [“x”, “x”] ].输入总是有效的。你可以假设除法运算中不会出现除数为0的情况,且不存在任何矛盾的结果。
并查集求解思路:
数学思想:将题目中给出的方程式换成连比的形式,如:a/b=2.0, b/c=3.0, 则 a: b : c=2:1:(1/3),因此很容易得出a/c=2/(1/3)=6.
编程思想:问题的关键是用怎样的数据结构来表示这个连比关系,一种比较好的办法是用 树,如:a/b=2.0, b/c=3.0,可以建树为:
整棵树存储到map中,map中的每一项存储树的结点名、该结点对应的数值以及该结点的父结点,如下图所示:
-
建树过程
这里举一个包括所有情况的例子:
equations(方程式) = [ [“a”, “b”], [“b”, “c”], [“e”,“c”], [“f”,“g”], [“e”,“g”] ],
values(方程式结果) = [2.0, 3.0, 2.0, 2.0, 3.0],
1)a/b=2.0:a和b都不在树中,则将a结点的值设为2.0,b结点的值设为1.0,a为b的父结点(a、b谁做父结点都一样,因为同一棵树中的所有结点表示一种连比关系),然后将两个结点存入map中;
2) b/c=3.0:c不在树中,若要跟树中的a, b形成连比关系,就要根据b的值来确定c的值(显然c的值为b/3.0),同时b作为c的父结点,然后将c插入树中;
3)e/c=2.0:e不在树中,若要跟树中的a, b, c构成连比关系,就要根据c的值来确定e的值(显然e的值为c*2.0), 同时c作为e的父结点,然后将e插入树中;
4)f/g=2.0:和1)同理,f的值设为2.0,g的值设为1.0,f为g的父结点,插入树中;
5)e/g=3.0:e和g分属于两棵树,这种情况比较复杂,直接上图:
在这里,我们需要根据e/g=3.0来将树①和树②合并成一棵树,也就是将两个连比关系合并成一个。不妨保持树②不动,按照相应的比例改变树①各值,然后合并。所以现在的重中之重是求出这个比例,既然树②各值不变,那么根据关系式e/g=3.0可以得出e的值应该变为g乘以3.0,由此e结点的值扩大(或者缩小)的倍数为g乘以3.0/(2/3),因此树①中每个结点的值都应该扩大(或者缩小)这个倍数。如下图:
建树完成! -
计算
根据这棵树便可以计算树中任意两结点之间的比值,特殊情况:若有结点不在树中,直接设置其结果为-1.0。 -
代码c++
class Solution {
private:
struct Node{
double val;
Node* parent;
Node():parent(this){}
Node(double v): val(v),parent(this){}
};
public:
Node* find_father(Node* n){
if (n->parent == n)
return n;
else
return find_father(n->parent);
}
void merge(Node* n1, Node* n2, double value,
unordered_map<string,Node*>& m){
Node* p1=find_father(n1), *p2=find_father(n2);
double ratio=value*n2->val/n1->val;
for(auto n : m){
if(find_father(n.second) == p1)
n.second->val*=ratio;
}
p1->parent = p2;
}
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
vector<double> res;
unordered_map<string, Node*> m;
for ( int i = 0; i < equations.size(); ++i ) {
string a = equations[i][0], b=equations[i][1];
if(m.find(a) == m.end() && m.find(b) == m.end()){
m[a] = new Node(values[i]);
m[b] = new Node(1.0);
m[b]->parent = m[a];
} else if (m.find(a) == m.end()) {
m[a] = new Node(values[i]*m[b]->val);
m[a]->parent = m[b];
} else if(m.find(b) == m.end()) {
m[b] = new Node(m[a]->val/values[i]);
m[b]->parent = m[a];
} else {
merge(m[a], m[b], values[i], m);
}
}
for (int i = 0; i < queries.size(); ++i) {
if (m.find(queries[i][0]) != m.end() && m.find(queries[i][1]) != m.end() && find_father(m[queries[i][0]]) == find_father(m[queries[i][1]])){
res.push_back(m[queries[i][0]]->val/m[queries[i][1]]->val);
} else {
res.push_back(-1.0);
}
}
return res;
}
};