【leetcode】399. 除法求值( Evaluate Division )


题目描述

【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> 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的情况,且不存在任何矛盾的结果。

第一次解答

思路
构建带权值边的并查集,对于每个方程式有两种情况

  1. 查询是否联通,若不联通,则答案为-1.0
  2. 若联通,则求出其与根相除的结果,根据结果计算方程式。

例如,对于题目示例:

  1. 构造并查集:a->b->c,其中a->b的边的权值为2.0,b->c的边的权值为3.0
  2. 以计算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;

    }
};

结果:
截图

相关/参考链接

你可能感兴趣的:(Leetcode,leetcode,并查集)