当前位置: 首页 > news >正文

力扣399题:除法求值

力扣399题:除法求值

题目描述

给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。

另有一些以数组 queries 表示的问题,其中 queries[j] = [Cj, Dj] 表示第 j 个问题,请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。

返回 所有问题的答案 。如果存在某个无法确定的答案,则用 -1.0 替代这个答案。如果问题中出现了给定的已知条件中没有出现的字符串,也需要用 -1.0 替代这个答案。

注意:输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。

输入输出样例

输入:equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
输出:[6.00000,0.50000,-1.00000,1.00000,-1.00000]
解释:
条件: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"],["bc","cd"]], values = [1.5,2.5,5.0], queries = [["a","c"],["c","b"],["bc","cd"],["cd","bc"]]
输出:[3.75000,0.40000,5.00000,0.20000]

输入:equations = [["a","b"]], values = [0.5], queries = [["a","b"],["b","a"],["a","c"],["x","y"]]
输出:[0.50000,2.00000,-1.00000,-1.00000]


提示:

1 <= equations.length <= 20
equations[i].length == 2
1 <= Ai.length, Bi.length <= 5
values.length == equations.length
0.0 < values[i] <= 20.0
1 <= queries.length <= 20
queries[i].length == 2
1 <= Cj.length, Dj.length <= 5
Ai, Bi, Cj, Dj 由小写英文字母与数字组成

解法一,使用并查集


//定义合并查询操作
class UnionFind{
private:

    //parent 存放父节点,weight 存放结点的值
    vector<int>parent;
    vector<double>weight;

public:

    //构造函数
    UnionFind(int n)
    {
        //限定容器的长度
        parent=vector<int>(n);
        weight=vector<double>(n);

//因为每一个根节点都指向其自己,所以父结点的权重为1.0
        for(int i=0;i<n;i++)
        {
            parent[i]=i;

            weight[i]=1.0;
        }
    }

//实现并查集的合并方法
    void myUnion(int x,int y,double value)
    {
        //首先查找两个结点对应根节点的id
        
        int rootX=find(x);
        int rootY=find(y);

        //如果二者根结点是一致的,那么就代表不用合并
        if(rootX==rootY)
        {
            return;
        }
        //否则将其中的根结节指向另一个根节点
        parent[rootX]=rootY;
        //利用两条路径上的有向边的权值的乘积相等的原则
        weight[rootX]=weight[y]*value/weight[x];
    }


//路径压缩
//实现并查集的find 方法,传入输入结点的id,返回根节点对应的id
    int find(int x)
    {
        //递归寻找到根节点,更新该点到根的权重为该点父节点到跟的权重

        if(x!=parent[x])
        {
            //保存上一个接待结点的权值
            int origin=parent[x];
            parent[x]=find(parent[x]);
            //更新到根节点的权值
            weight[x]*=weight[origin];
        }
        return parent[x];
    }

//实现除法结果。如果两个值不存在则返回-1
    double isConnected(int x,int y)
    {
        //判断二则的根节点是否相同,若有相同的根可执行除法操作,若无,则二者不在一个并查集,返回-1
        int rootX=find(x);
        int rootY=find(y);

        if(rootX==rootY)
        {
            return weight[x]/weight[y];
        }
        else{
            return -1.0000;
        }
    }

};






class Solution2 {
public:

//使用并查集
//构建有向图 b/c=3.0  parent[b]=c  weight[b]=3.0
//统一变量与路径压缩
//两条路径上的有向边的权值的乘积是一定相等的

    vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
        int equationsSize=equations.size();
        
        //实例化并查集
        //2*equationSize 最极端的情况,都不相同
        UnionFind unionFind(2*equationsSize);
        unordered_map<string,int>maps(2*equationsSize);
        //使用id标记变量
        int id=0;

        for(int i=0;i<equationsSize;i++)
        {
            //将equations中的变量存储进来
            vector<string>equation=equations[i];
            string var1=equation[0];
            string var2=equation[1];

            //将变量放入hash表中
            if(!maps.count(var1))
            {
                maps[var1]=id;
                id++;
            }
            if(!maps.count(var2))
            {
                maps[var2]=id;
                id++;
            }

            //在并查集中执行一次合并的操作
            //将分子分母用有向边连接起来
            unionFind.myUnion(maps[var1],maps[var2],values[i]);
        }

                //进行查询操作票
        int queriesSize=queries.size();
        vector<double>res(queriesSize,-1.0000);
        for(int i=0;i<queriesSize;i++)
        {
            string var1=queries[i][0];
            string var2=queries[i][1];

            if(maps.count(var1)&&maps.count(var2))
            {
                int id1=maps[var1];
                int id2=maps[var2];
                res[i]=unionFind.isConnected(id1,id2);
            }
            else{
                res[i]=-1.0000;
            }
        }
        return res;

    }
};

解法二,使用广度优先搜索


//使用广度优先搜索
class Solution {
public:
//将整个问题建模成图,给定图中的一些点,以及某些边的权值(两个变量的比值)
//对任意两点(两个变量)求出其路径长(两个变量的壁纸)
    vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
        //使用id标记结点
        int id=0;
        unordered_map<string,int>maps;

        int equationLength=equations.size();

        //将表达式添加到hash表中
        for(int i=0;i<equationLength;i++)
        {
            if(!maps.count(equations[i][0]))
            {
                maps[equations[i][0]]=id++;
            }

            if(!maps.count(equations[i][1]))
            {
                maps[equations[i][1]]=id++;
            }            
        }

        //边中存储每个点其直接连接的点和对应的权值
        vector<vector<pair<int,double>>>edges(id);

        for(int i=0;i<equationLength;i++)
        {
            int temp1=maps[equations[i][0]];
            int temp2=maps[equations[i][1]];

            edges[temp1].push_back({temp2,values[i]});
            edges[temp2].push_back({temp1,1.0/values[i]});
        }


        vector<double>res;
        for(const auto &q:queries)
        {
            double result=-1.0;

            //如果hash表中存在对应的结点
            if(maps.count(q[0])&&maps.count(q[1]))
            {
                int id1=maps[q[0]];
                int id2=maps[q[1]];

                //如果二者id相同,二者肯定相同
                if(id1==id2)
                {
                    result=1.0;
                }
                else
                {
                    //建立队列进行辅助
                    queue<int>points;

                    points.push(id1);

                    vector<double>ratios(id,-1.0);
                    ratios[id1]=1.0;

                    while(!points.empty()&&ratios[id2]<0)
                    {
                        int x=points.front();
                        points.pop();

                        for( auto [y,val]:edges[x])
                        {
                            if(ratios[y]<0)
                            {
                                ratios[y]=ratios[x]*val;
                                points.push(y);
                            }
                        }
                    }
                    result=ratios[id2];
                }
            }
            res.push_back(result);
        }
        return res;
    }
};

解法三,使用Floyd算法

//使用Floyd算法
class Solution3 {
public:
//将整个问题建模成图,给定图中的一些点,以及某些边的权值(两个变量的比值)
//使用Floyd算法,预先计算出任意两点之间的距离
    vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
        int id=0;
        unordered_map<string,int>maps;

        int equationLength=equations.size();
                //将表达式添加到hash表中
        for(int i=0;i<equationLength;i++)
        {
            if(!maps.count(equations[i][0]))
            {
                maps[equations[i][0]]=id++;
            }

            if(!maps.count(equations[i][1]))
            {
                maps[equations[i][1]]=id++;
            }            
        }

    //绘制图
        vector<vector<double>>graph(id,vector<double>(id,-1.0));
        for(int i=0;i<equationLength;i++)
        {
            int id1=maps[equations[i][0]];
            int id2=maps[equations[i][1]];
            graph[id1][id2]=values[i];
            graph[id2][id1]=1.0/values[i];
        }

    //对图进行预处理,将各个顶点连接在一块
        for(int k=0;k<id;k++)
        {
            for(int i=0;i<id;i++)
            {
                for(int j=0;j<id;j++)
                {
                    if(graph[i][k]>0&&graph[k][j]>0)
                    {
                        graph[i][j]=graph[i][k]*graph[k][j];
                    }
                }
            }
        }

        //计算结果
        vector<double>res;
        for(auto q:queries)
        {
            double result=-1.0;
            if(maps.count(q[0])&&maps.count(q[1]))
            {
                int id1=maps[q[0]];
                int id2=maps[q[1]];

                if(graph[id1][id2]>0)
                {
                    result=graph[id1][id2];
                }
            }
            res.push_back(result);
        }
        return res;

    }
};

相关文章:

  • R语言商业推荐系统实战
  • ​力扣解法汇总946-验证栈序列
  • PMP每日一练 | 考试不迷路-8.31(包含敏捷+多选)
  • 【Java第24期】:IO、存储、硬盘和文件系统的相关知识
  • ZLMediaKit学习(一):Window环境下推拉流
  • voip|网络电话,软件实现电信座机
  • 天玑810和天玑800u哪个好 天玑810和天玑800u差多少
  • Sulfo-Cy3 NHS酯,Sulfo-Cy3 NHS ester,水溶性荧光染料Cy3标记琥珀酰亚胺活化酯
  • Python输入漏洞利用(Python input漏洞)
  • 重启tomcat-Tomcat服务器怎么重启?
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • SQL(及存储过程)跑得太慢怎么办?
  • 如何选择国际通知短信服务商?
  • RocketMQ回顾整理
  • 【大数据分析】FordFulkerson算法(JAVA实现)
  • CSS实用技巧干货
  • C语言笔记(第一章:C语言编程)
  • Git学习与使用心得(1)—— 初始化
  • MySQL的数据类型
  • oschina
  • overflow: hidden IE7无效
  • React-flux杂记
  • React-Native - 收藏集 - 掘金
  • SpringBoot几种定时任务的实现方式
  • 百度小程序遇到的问题
  • 闭包,sync使用细节
  • 对象引论
  • 你不可错过的前端面试题(一)
  • 七牛云 DV OV EV SSL 证书上线,限时折扣低至 6.75 折!
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 使用 QuickBI 搭建酷炫可视化分析
  • 使用权重正则化较少模型过拟合
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 正则表达式小结
  • #{}和${}的区别是什么 -- java面试
  • #14vue3生成表单并跳转到外部地址的方式
  • #DBA杂记1
  • (3)llvm ir转换过程
  • (9)目标检测_SSD的原理
  • (SpringBoot)第二章:Spring创建和使用
  • (WSI分类)WSI分类文献小综述 2024
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (安卓)跳转应用市场APP详情页的方式
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (转)ObjectiveC 深浅拷贝学习
  • (转)创业家杂志:UCWEB天使第一步
  • .NET Compact Framework 多线程环境下的UI异步刷新
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • ::
  • @RequestMapping处理请求异常
  • @require_PUTNameError: name ‘require_PUT‘ is not defined 解决方法
  • [ CTF ] WriteUp- 2022年第三届“网鼎杯”网络安全大赛(白虎组)
  • [@Controller]4 详解@ModelAttribute
  • []指针