-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path0399-Evaluate_Division.cpp
More file actions
159 lines (145 loc) · 4.75 KB
/
0399-Evaluate_Division.cpp
File metadata and controls
159 lines (145 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*******************************************************************************
* 0399-Evaluate_Division.cpp
* Billy.Ljm
* 20 May 2023
*
* =======
* Problem
* =======
* https://leetcode.com/problems/evaluate-division/
*
* You are given an array of variable pairs equations and an array of real
* numbers values, where equations[i] = [Ai, Bi] and values[i] represent the
* equation Ai / Bi = values[i]. Each Ai or Bi is a string that represents a
* single variable.
*
* You are also given some queries, where queries[j] = [Cj, Dj] represents the
* jth query where you must find the answer for Cj / Dj = ?.
*
* Return the answers to all queries. If a single answer cannot be determined,
* return -1.0.
*
* ===========
* My Approach
* ===========
* We can view this problem as a directed graph, where the numerator/denominator
* indicate the direction of the graph. For example, finding A/C is equivalent
* to find a path from the node A to C, such as A to B to C which would
* correspond to A/B * B/C. Then, we just have to find a path between the
* desired nodes, which I'll do with a recursive depth-first search.
*
* This has a time complexity of O(e * q) and space complexity of O(e), where
* e is the number of equations and q the number of queries.
******************************************************************************/
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <set>
using namespace std;
/**
* Solution
*/
class Solution {
private:
/**
* Recursively search for node in graph
*
* @param val current value, will be multiplied by next edge
* @param node current node to search from
* @param dest final node to stop at
* @param visited nodes visited already
* @param graph graph[A][B] = A/B
*
* @return product of all edges of found path, or -1.0 if dest not found
*/
double recurse(double val, string node, string dest, set<string>& visited,
unordered_map<string, unordered_map<string, double>>& graph) {
// if destination found (and they're valid), return value
if (node == dest and graph.find(node) != graph.end()) {
return val;
}
// else recurse through all unvisited neighbours
double tmp;
for (auto it : graph[node]) {
if (visited.find(it.first) == visited.end()) {
visited.insert(it.first);
tmp = recurse(val * it.second, it.first, dest, visited, graph);
if (tmp != -1.0) return tmp; // if destination found, echo value
}
}
// destination not found in all neighbours, return -1
return -1.0;
}
public:
/**
* Evaulates the fractions b/w two algebraic variables based on a set of
* other known fractions
*
* @param equations known equations[i] = [numerator[i], denominator[i]]
* @param values known values[i] = numerator[i] / denominator[i]
* @param queries unknown queries[i] = [qnumerator[i], qdenominator[i]]
*
* @return unknown qvalues[i] = qnumerator[i] / qdenominator[i]
*/
vector<double> calcEquation(
vector<vector<string>>& equations,
vector<double>& values,
vector<vector<string>>& queries) {
// build graph (graph[A][B] = A/B)
unordered_map<string, unordered_map<string, double>> graph;
for (int i = 0; i < equations.size(); i++) {
graph[equations[i][0]][equations[i][1]] = values[i];
graph[equations[i][1]][equations[i][0]] = 1 / values[i];
}
// answer queries
set<string> visited;
vector<double> answers;
for (int i = 0; i < queries.size(); i++) {
visited.clear();
answers.push_back(recurse(1, queries[i][0], queries[i][1], visited,
graph));
}
return answers;
}
};
/**
* << operator for vectors
*/
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
os << "[";
for (int i = 0; i < v.size(); i++) {
os << v[i] << ",";
}
os << "\b]";
return os;
}
/**
* Test cases
*/
int main(void) {
Solution sol;
vector<vector<string>> equations;
vector<double> values;
vector<vector<string>> queries;
// test case 1
equations = { {"a", "b"}, {"b", "c"} };
values = { 2.0, 3.0 };
queries = { {"a", "c"}, {"b", "a"}, {"a", "e"}, {"a", "a"}, {"x", "x"} };
cout << "calcEquation(" << equations << "," << values << "," << queries
<< ") = " << sol.calcEquation(equations, values, queries) << endl;
// test case 2
equations = { {"a", "b"}, {"b", "c"}, {"bc", "cd"} };
values = { 1.5, 2.5, 5.0 };
queries = { {"a", "c"}, {"c", "b"}, {"bc", "cd"}, {"cd", "bc"} };
cout << "calcEquation(" << equations << "," << values << "," << queries
<< ") = " << sol.calcEquation(equations, values, queries) << endl;
// test case 3;
equations = { {"a", "b"} };
values = { 0.5 };
queries = { {"a", "b"}, {"b", "a"}, {"a", "c"}, {"x", "y"} };
cout << "calcEquation(" << equations << "," << values << "," << queries
<< ") = " << sol.calcEquation(equations, values, queries) << endl;
return 0;
}