leetcode 399.除法求值

399. 除法求值

  • 题目
  • 分析
    • 建立
      • find函数
      • union函数
    • 查询
    • 改进

题目

给出方程式 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, vector& values, vector> queries(方程式,方程式结果,问题方程式), 其中 equations.size() == values.size(),即方程式的长度与方程式结果长度相等(程式与结果一一对应),并且结果值均为正数。以上为方程式的描述。 返回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函数

使用find函数可以得到一个根节点和到根节点的比值,通过节点不断向根节点回溯以及比值乘法进行

union函数

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;

    }
};

你可能感兴趣的:(leetcode 399.除法求值)