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. Windows Phone 8.1又有什么新花样

    今年微软新任CEO提出了“Mobile First and Cloud First”的发展战略,随着微软Mobile First战略的实行,开发者是时候重视Windows Phone了.你可能不相信, ...

  2. 使用 NuGet 下载最新的 Rafy 框架及文档

    为了让开发者更方便地使用 Rafy 领域实体框架,本月,我们已经把最新版本的 Rafy 框架程序集发布到了 nuget.org 上,同时,还把 RafySDK 的最新版本发布到了 VisualStud ...

  3. 前端开发:setTimeout与setInterval 定时器与异步循环数组

    前端开发:setTimeout与setInterval 定时器与异步循环数组 前言: 开通博客园三个月以来,随笔记录了工作中遇到的大大小小的难题,也看过无数篇令人启发的文章,我觉得这样的环境是极好的, ...

  4. JavaScript弹窗

    警告框: alert("警告信息!"); alert("警告\n信息!"); 确认框: var t=confirm("请确认!"); // ...

  5. 判断IEnumerable<T>集合中是否包含有T对象

    比如,有角色集合中,只有用户创建有角色,才出现“分配”铵钮.反之,隐藏. IEnumerable有一个方法,叫Any:

  6. atom配置web开发环境

    1. 安装包 1.1 apm命令 自带apm ,没有菜单栏找install shell commands apm全称:atom package management apm installl [包的名 ...

  7. 初识html5的localStorage本地存储

    一.概述 HTML5 提供了两种在客户端存储数据的新方法: localStorage - 没有时间限制的数据存储 sessionStorage - 针对一个 session 的数据存储 之前,这些都是 ...

  8. Oracle研究专题:Oracle系统安装与配置

    最近开始研究Oracle数据库,盖因公司的系统要么Oracle要么是mysql吧. 作为一个IT工作者,没有碰过Oracle是一件很匪夷所思得事情. 想到过去几年,乃至接触IT行业开始就只有玩过sql ...

  9. ipython notebook 浏览器中编写数学公式和现实

    Python Notebook简介1 http://www.cnblogs.com/cbscan/p/3545084.html $ python -m IPython http://pypi.pyth ...

  10. UITabBarController 基本定制

    UITabBarController 定制 特点 用法 1.准备好你的tabBar图片及其他图片(哈哈哈!!!!),我的图片都放在了Assets.xcassets中. 2.导入本工程中的Categro ...