[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 ,如需转载请自行联系原博主。

相关文章
|
6月前
|
算法 Go
golang力扣leetcode 399.除法求值
golang力扣leetcode 399.除法求值
57 0
|
5月前
|
存储 算法 数据挖掘
深入解析力扣166题:分数到小数(模拟长除法与字符串操作详解及模拟面试问答)
深入解析力扣166题:分数到小数(模拟长除法与字符串操作详解及模拟面试问答)
|
6月前
|
存储 人工智能 BI
leetcode 399 除法求值
leetcode 399 除法求值
36 1
|
测试技术
LeetCode-553 最优除法
LeetCode-553 最优除法
|
6月前
|
SQL
leetcode-SQL-1440. 计算布尔表达式的值
leetcode-SQL-1440. 计算布尔表达式的值
62 1
|
6月前
leetcode-1106: 解析布尔表达式
leetcode-1106: 解析布尔表达式
44 0
|
6月前
|
人工智能 BI
leetcode-399:除法求值
leetcode-399:除法求值
67 0
|
6月前
|
测试技术
leetcode-241:为运算表达式设计优先级
leetcode-241:为运算表达式设计优先级
33 0
|
6月前
leetcode-553:最优除法
leetcode-553:最优除法
38 0