给出方程式 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
基于上述例子,输入如下:
equations(方程式) = [ [“a”, “b”], [“b”, “c”] ],
values(方程式结果) = [2.0, 3.0],
queries(问题方程式) = [ [“a”, “c”], [“b”, “a”], [“a”, “e”], [“a”, “a”], [“x”, “x”] ].
输入总是有效的。你可以假设除法运算中不会出现除数为0的情况,且不存在任何矛盾的结果。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/evaluate-division
这道题目是图的路径问题,准确的说是森林的问题.图上的路径a/c就是(a/b) / (b/c)就是a->b->c只不过路径的权值是乘法,但由于是树,所以权值唯一.
可以使用dfs但是使用naive方法每次搜索可能会挂,需要有记录的dfs,或者使用弗洛伊德算法,计算所有点之间的路径,在此我使用的是并查集的方法.
这道题目和常规的并查集的区别是他带有权值,而不是简单的同类关系,题目分成两个部分,并查集的建立,以及后面的查询
因为这个需要有权值的记录,所以使用weight来记录点到根的比值,使用par来记录父子关系,而这两个值是一一对应的,就比如对于点c par[“c”]=“b”,weight[“c”]=10,就表示c点到自己的祖辈节点b的比值为10,这个b可能是上一个节点,也可能是树的根节点,但一定是c的祖辈这样我们的weight有一个依赖,不至于混乱.
遍历所有的边(a,b),首先检查边的两点是否存在,不存在就创建一个,之后检查两点是否是同一个集合,
使用find函数可以得到一个根节点和到根节点的比值,通过节点不断向根节点回溯以及比值乘法进行
union函数合并两个不属于同一集合的树,把一个其中一个的根节点当作另外一个根节点的父节点,因为父子节点改变,weight也要改变权值.更新的公式weight[xx.first]=dyy.second/xx.second;
假设a/b=2,c/d=3,又知b/d=4,那么经过a和c的比值就是(a/b)(b/d)/(c/d),就是上面的公式,其中
xx.second=c/d,就是不是作为主根节点的比值,yy.second=(a/b)
查询就是很简单的常规查询,检查两点是否在同一个集合中,在就权值相除,因为都是对于根节点来说的,不在就输出-1.0
class Solution {
public:
int sz;
unordered_map<string,string> par;
unordered_map<string,double> weight;
pair<string,double> find(string p)
{
if(par.find(p)==par.end())
return {
"",-1.0};
string tmp=p;
double div=1.0;
while(tmp!=par[tmp])
{
div*=weight[tmp];
tmp=par[tmp];
}
return {
tmp,div};
}
bool union1(string x,string y,double d)
{
auto xx=find(x),yy=find(y);
if(xx.first==yy.first)
return false;
par[xx.first]=yy.first;
weight[xx.first]=d*yy.second/xx.second;
return true;
}
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
sz=equations.size();
for(int i=0;i<sz;i++)
{
string a=equations[i][0],b=equations[i][1];
if(par.find(a)==par.end())
{
par[a]=a;
weight[a]=1.0;
}
if(par.find(b)==par.end())
{
par[b]=b;
weight[b]=1.0;
}
union1(a,b,values[i]);
}
vector<double> ans;
for(int i=0;i<queries.size();i++)
{
string ta=queries[i][0],tb=queries[i][1];
auto aa=find(ta),bb=find(tb);
if(aa.first==""||aa.first!=bb.first)
{
ans.push_back(-1.0);
}
else
{
ans.push_back(aa.second/bb.second);
}
}
//ans.push_back(div[par["b"]]);
return ans;
}
};