算法练习(5) —— 图
习题
本次题目取自leetcode中的 Graph
栏目中的第399题:
Evaluate Division
题目如下:
Description
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. Returnvector<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.
思路与代码
- 理解题意并不难,就是给你一堆已有的算式,再给你一些新的算式,求出其答案,能推出来就输出答案,推不出来就输出-1…
- 首先要注意几点
- 输入绝对有效
- 知道
a / b
, 也就知道了b / a
- 在上面那个条件下, 可能有
0 / b = 0
的情况,这时候b / 0
是不允许的
- 做这个题目最直观的想法是将每个除数和被除数当作结点,连接起来,构成一个图。每次先寻找初始节点,如果找不到直接返回-1。接下来开始找目标节点,能联通的不断做除法或者乘法就行,不能联通的直接赋值为-1。
- 第二个想法是比较幼稚但是效率很高的方法…把除数或者被除数赋个初始值,然后算出对应的另一个…也就是把所给的所有的已有算式,转化在同一个坐标系下,对应的比率都是一样的。例如:
equations : [["a", "b"], ["b", "c"]]
values : [2.0, 5.0]
一开始从equations的第一个被除数 a 赋值, 令 a = 1.0, 则 b = a / 2.0 = 0.5, c = b / 5.0 = 0.1
这样在求a / c或者 c / a的时候, 就不需要从两个算式之间去转换, 直接用对应的数字去算就OK了
- 上面那个方法看似简单,但是有个很大的弊病就是有可能出现除不尽的情况,有的乘回来能恢复,有的就说不定了…不过我觉得可行性很高,不知道提交能不能通过测试样例呢…
- 最后我采用了另外一种方法。因为hash map可以用string作key存储信息,寻找方面很方便,操作也很方便。存储
a / b = value
的信息时,可以存储key = a, v = value
时的顺便存储key = b, v = 1 / value
。hash map 在 c++ 中对应的是unordered_map
代码如下:
#include <vector>
#include <unordered_map>
#include <set>
using namespace std;
class Solution {
public:
vector<double> calcEquation(vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries) {
unordered_map<string, unordered_map<string, double>> hashMap;
vector<double> result;
for (int i = 0; i < equations.size(); i++) {
// 存储 a / b
hashMap[equations[i].first].insert(make_pair(equations[i].second, values[i]));
// 存储 b / a
if (values[i] != 0)
hashMap[equations[i].second].insert(make_pair(equations[i].first, 1 / values[i]));
}
for (int j = 0; j < queries.size(); j++) {
set<string> s;
// dfs
double ans = findPath(queries[j].first, queries[j].second, hashMap, s);
if (ans)
result.push_back(ans);
else
result.push_back(-1);
}
return result;
}
double findPath(string first, string second, unordered_map<string, unordered_map<string, double>>& hashMap, set<string>& s) {
if (hashMap[first].find(second) != hashMap[first].end())
return hashMap[first][second];
for (auto sec : hashMap[first]) {
if (s.find(sec.first) == s.end()) {
s.insert(sec.first);
double ans = findPath(sec.first, second, hashMap, s);
if (ans)
return sec.second * ans;
}
}
return 0;
}
};