[LeetCode] Evaluate Division 求除法表达式的值

Equations are given in the format A / B = k, where A and B are variables represented as strings, and k is a real number (floating point number). Given some queries, return the answers. If the answer does not exist, return -1.0.

Example:
Given a / b = 2.0, b / c = 3.0. 
queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? . 
return [6.0, 0.5, -1.0, 1.0, -1.0 ].

The input is: vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries , whereequations.size() == values.size(), and the values are positive. This represents the equations. Return vector<double>.

According to the example above:

equations = [ ["a", "b"], ["b", "c"] ],
values = [2.0, 3.0],
queries = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ]. 

The input is always valid. You may assume that evaluating the queries will result in no division by zero and there is no contradiction.

这道题作为第四次编程比赛的压轴题,感觉还是挺有难度的,个人感觉难度应该设为hard比较合理。这道题已知条件中给了一些除法等式,然后给了另外一些除法等式,问我们能不能根据已知条件求出结果,不能的用-1表示。问题本身是很简单的数学问题,但是写代码来自动实现就需要我们用正确的数据结构和算法,通过观察题目中的例子,我们可以看出如果需要分析的除法式的除数和被除数如果其中任意一个没有在已知条件中出现过,那么返回结果-1,所以我们在分析已知条件的时候,可以使用set来记录所有出现过的字符串,然后我们在分析其他除法式的时候,可以使用递归来做。通过分析得出,不能直接由已知条件得到的情况主要有下面三种:

1) 已知: a / b = 2, b / c = 3, 求 a / c
2) 已知: a / c = 2, b / c = 3, 求 a / b
3) 已知: a / b = 2, a / c = 3, 求 b / c

在递归函数中,我们有一个需要分析的除法表达式,我们遍历所有的已知条件,如果跟某一个已知表达式相等,直接返回结果,或者跟某一个已知表达式正好相反,那么返回已知表达式结果的倒数即可。如果都没有的话,那么就需要间接寻找了,我们需要一个vector来记录已经访问过的表达式,我们先看待求表达式的被除数和当前遍历到的已知表达式的被除数是否相同如果相同,那么就是上面的第一种情况,我们就可以把待求表达式的被输出换成已知表达式的除数,比如要求a/c就换成了求b/c,而求b/c的过程就可以调用递归函数来求解,结果要乘以a/b的值。如果算出来是正数我们直接返回,如果是非正数说明没有找到。对于上面的第一种情况,如果我们要求c/a,那么上面的方法就没法开始查找,所以我们同时也要看待求表达式的除数和当前遍历到的已知表达式的被除数是否相同,后面的处理方法都相同,参见代码如下:

解法一:

class Solution {
public:
    vector<double> calcEquation(vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries) {
        vector<double> res(queries.size(), -1);
        set<string> s;
        for (auto a : equations) {
            s.insert(a.first);
            s.insert(a.second);
        }
        for (int i = 0; i < queries.size(); ++i) {
            vector<string> query{queries[i].first, queries[i].second};
            if (s.count(query[0]) && s.count(query[1])) {
                vector<int> v;
                res[i] = helper(equations, values, query, v);
            }   
        }
        return res;
    }
    double helper(vector<pair<string, string>> equations, vector<double>& values, vector<string> query, vector<int>& v) {
        for (int i = 0; i < equations.size(); ++i) {
            if (equations[i].first == query[0] && equations[i].second == query[1]) return values[i];
            if (equations[i].first == query[1] && equations[i].second == query[0]) return 1.0 / values[i];
        }
        for (int i = 0; i < equations.size(); ++i) {
            if (find(v.begin(), v.end(), i) == v.end() && equations[i].first == query[0]) {
                v.push_back(i);
                double t = values[i] * helper(equations, values, {equations[i].second, query[1]}, v);
                if (t > 0) return t;
                else v.pop_back();
            }
            if (find(v.begin(), v.end(), i) == v.end() && equations[i].second == query[0]) {
                v.push_back(i);
                double t = helper(equations, values, {equations[i].first, query[1]}, v) / values[i];
                if (t > 0) return t;
                else v.pop_back();
            }
        }
        return -1.0;
    }
};

此题还有迭代的写法,用邻接列表的表示方法建立了一个图,然后进行bfs搜索,需要用queue来辅助运算,参见代码如下:

解法二:

class Solution {
public:
    vector<double> calcEquation(vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries) {
        vector<double> res;
        unordered_map<string, unordered_map<string, double>> g;
        for (int i = 0; i < equations.size(); ++i) {
            g[equations[i].first].emplace(equations[i].second, values[i]);
            g[equations[i].first].emplace(equations[i].first, 1.0);
            g[equations[i].second].emplace(equations[i].first, 1.0 / values[i]);
            g[equations[i].second].emplace(equations[i].second, 1.0);
        }
        for (auto query : queries) {
            if (!g.count(query.first) || !g.count(query.second)) res.push_back(-1.0);
            else {
                queue<pair<string, double>> q;
                unordered_set<string> used{query.first};
                bool find = false;
                q.push({query.first, 1.0});
                while (!q.empty() && !find) {
                    queue<pair<string, double>> next;
                    while (!q.empty() && !find) {
                        pair<string, double> t = q.front(); q.pop();
                        if (t.first == query.second) {
                            find = true;
                            res.push_back(t.second);
                            break;
                        }
                        for (auto a : g[t.first]) {
                            if (!used.count(a.first)) {
                                a.second *= t.second;
                                next.push(a);
                                used.insert(a.first);
                            }
                        }
                    }
                    q = next;
                }
                if (!find) res.push_back(-1.0);
            }
        }
        return res;
    }
};

本文转自博客园Grandyang的博客,原文链接:求除法表达式的值[LeetCode] Evaluate Division ,如需转载请自行联系原博主。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值