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 , where equations.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

虽然有三种情况,但其实后两种情况都可以转换为第一种情况,对于每个已知条件,我们将其翻转一下也存起来,那么对于对于上面美中情况,就有四个已知条件了:

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

我们发现,第二种和第三种情况也能转化为第一种情况,只需将上面加粗的两个条件相乘即可。对于每一个需要解析的表达式,我们需要一个HashSet来记录已经访问过的表达式,然后对其调用递归函数。在递归函数中,我们在HashMap中快速查找该表达式,如果跟某一个已知表达式相等,直接返回结果。如果没有的话,那么就需要间接寻找了,我们在HashMap中遍历跟解析式中分子相同的已知条件,跳过之前已经遍历过的,否则就加入visited数组,然后再对其调用递归函数,如果返回值是正数,则乘以当前已知条件的值返回,就类似上面的情况一,相乘以后b就消掉了。如果已知找不到解,最后就返回-1,参见代码如下:

解法一:

class Solution {
public:
vector<double> calcEquation(vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries) {
vector<double> res;
for (int i = ; i < equations.size(); ++i) {
m[equations[i].first][equations[i].second] = values[i];
m[equations[i].second][equations[i].first] = 1.0 / values[i];
}
for (auto query : queries) {
unordered_set<string> visited;
double t = helper(query.first, query.second, visited);
res.push_back((t > 0.0) ? t : -);
}
return res;
}
double helper(string up, string down, unordered_set<string>& visited) {
if (m[up].count(down)) return m[up][down];
for (auto a : m[up]) {
if (visited.count(a.first)) continue;
visited.insert(a.first);
double t = helper(a.first, down, visited);
if (t > 0.0) return t * a.second;
}
return -1.0;
} private:
unordered_map<string, unordered_map<string, double>> m;
};

此题还有迭代的写法,用邻接列表的表示方法建立了一个图,然后进行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 = ; 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);
continue;
}
queue<pair<string, double>> q;
unordered_set<string> visited{query.first};
bool found = false;
q.push({query.first, 1.0});
while (!q.empty() && !found) {
for (int i = q.size(); i > ; --i) {
auto t = q.front(); q.pop();
if (t.first == query.second) {
found = true;
res.push_back(t.second);
break;
}
for (auto a : g[t.first]) {
if (visited.count(a.first)) continue;
visited.insert(a.first);
a.second *= t.second;
q.push(a);
}
}
}
if (!found) res.push_back(-1.0);
}
return res;
}
};

参考资料:

https://leetcode.com/problems/evaluate-division/

https://leetcode.com/problems/evaluate-division/discuss/88347/c-bfs-solution-easy-to-understand

https://leetcode.com/problems/evaluate-division/discuss/88287/esay-understand-java-solution-3ms

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Evaluate Division 求除法表达式的值的更多相关文章

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

    Equations are given in the format A / B = k, where A and B are variables represented as strings, and ...

  2. pat02-线性结构3. 求前缀表达式的值(25)

    02-线性结构3. 求前缀表达式的值(25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 算术表达式有前缀表示法.中缀表示法和后缀表示法 ...

  3. PTA笔记 堆栈模拟队列+求前缀表达式的值

    基础实验 3-2.5 堆栈模拟队列 (25 分) 设已知有两个堆栈S1和S2,请用这两个堆栈模拟出一个队列Q. 所谓用堆栈模拟队列,实际上就是通过调用堆栈的下列操作函数: int IsFull(Sta ...

  4. 信息竞赛进阶指南--递归法求中缀表达式的值,O(n^2)(模板)

    // 递归法求中缀表达式的值,O(n^2) int calc(int l, int r) { // 寻找未被任何括号包含的最后一个加减号 for (int i = r, j = 0; i >= ...

  5. 【Zhejiang University PATest】02-3. 求前缀表达式的值

    算术表达式有前缀表示法.中缀表示法和后缀表示法等形式.前缀表达式指二元运算符位于两个运算数之前,例如2+3*(7-4)+8/4的前缀表达式是:+ + 2 * 3 - 7 4 / 8 4.请设计程序计算 ...

  6. openjduge 求简单表达式的值

    表达式求值 总时间限制:  10000ms  单个测试点时间限制:  1000ms  内存限制:  131072kB 给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值. 输入 输入仅有一行 ...

  7. K:双栈法求算术表达式的值

    相关介绍:  该算法用于求得一个字符串形式的表达式的结果.例如,计算1+1+(3-1)*3-(21-20)/2所得的表达式的值,该算法利用了两个栈来计算表达式的值,为此,称为双栈法,其实现简单且易于理 ...

  8. 3-07. 求前缀表达式的值(25) (ZJU_PAT数学)

    题目链接:http://pat.zju.edu.cn/contests/ds/3-07 算术表达式有前缀表示法.中缀表示法和后缀表示法等形式.前缀表达式指二元运算符位于两个运算数之前,比如2+3*(7 ...

  9. Leetcode: Evaluate Division

    Equations are given in the format A / B = k, where A and B are variables represented as strings, and ...

随机推荐

  1. 挣值管理 EVM

    项目的挣值管理(Earned Value Management,EVM),是用与进度计划.成本预算和实际成本相联系的三个独立的变量,进行项目绩效测量的一种方法. 有三个比较重要的参数,用这三个参数能够 ...

  2. 外边距塌陷之clearance

    在一个BFC中,垂直方向上相邻的块级盒子产生外边距塌陷,本文要说一个特殊的外边距塌陷情况,即当垂直方向上,两个块级盒子之间有个浮动元素相隔时,这个时候会产生什么样的效果呢? .outer{ overf ...

  3. Lua BehaviourTree 各节点说明

    项目说明 本行为树的代码使用Lua编写,所有的内容也建立的Lua的基础语法之上 因为公司项目需求,需要一套Lua的行为树代码,所以尝试从饥荒中抽离了行为树相关的代码.绝大多数节点行为与饥荒中相同,不过 ...

  4. C#/ASP.NET完善的DBHelper,配套Model生成器

    支持Oracle.MSSQL.MySQL.SQLite四种数据库,支持事务,支持对象关系映射:已在多个项目中实际使用. 没有语法糖,学习成本几乎为0,拿来即用. DBHelper类完整代码: usin ...

  5. python学习笔记1:python入门

    关于版本的选择 按照网上的说法,如果python是为了在工作中使用,选择2.7版本的.这里我选择2.7.9版本的来进行学习: Python是什么? 是一种高级的计算机程序设计语言.应用范围比较广,go ...

  6. Elastic学习第一天遇到的问题以及添加的一些操作

    1.刚开始安装好了之后,启动之后, 报错: ERROR: max file descriptors [] ] 需要设置max file descriptors为65536,出现这个是因为普通的用户是1 ...

  7. vs2013\2015UML系列之-类图

    1.UML简介Unified Modeling Language (UML)又称统一建模语言或标准建模语言. 简单说就是以图形方式表现模型,根据不同模型进行分类,在UML 2.0中有13种图,以下是他 ...

  8. 初窥Javascript单元测试,附带掌握一门新技能的学习方式。

    之前没感觉要学啥单元测试,项目中测试都是手动测的,但也没觉的啥,但最近看文章和招聘上也多多少少有这方面的需求,于是网上搜索了一下,只找到了一些文章,但介绍的都不是很详细或者说比较复杂,满满的伤,虽然看 ...

  9. 如何解决MSI类型的Sharepoint Server2016 安装即点即用的office 2016 plus问题

    前提 在sharepoint server 2016安装office 2016 plus提示如下错误: 解决方法 Ø 概念 1. 即点和即用的概念:即点即用是一种通过 Internet 安装和更新 O ...

  10. React Native之 Navigator与NavigatorIOS使用

    前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...