399. 除法求值

算法内容

本文件实现 LeetCode 399「除法求值」。方程 a / b = value 可以看作带权有向图中的两条边:a -> b 权重为 value,b -> a 权重为倒数。

代码先构建变量名到节点索引的映射,并为每个变量维护相邻节点和边权。查询时,如果变量不存在返回 -1;如果起点终点相同返回 1;否则从起点做图搜索,沿路径累计乘积,找到目标节点时返回路径权重乘积。构图复杂度 O(E),单次查询最坏 O(V + E)。文件中还包含打印图结构和本地测试的辅助代码。

算法实现

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


#include<vector>
#include<iostream>
#include<stack>
#include<queue>
#include<algorithm>
#include<unordered_map>

using namespace std;

struct GraphNode {
string name;
vector<GraphNode*> children;
unordered_map<string, double> values;

void addChildren(GraphNode* node, double val) {
children.push_back(node);
values[node->name] = val;
}
GraphNode(string name0): name(name0) {}
};

class Solution {
public:
unordered_map<string, int> index;
vector<GraphNode*> g;
int len;
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
int equationNum = equations.size();
int count = 0;
for(int i = 0; i < equationNum; i++) {
string node1Name = equations[i][0],node2Name = equations[i][1];
double value1 = values[i], value2 = 1/values[i];
GraphNode *node1, *node2;
if(index.count(node1Name) == 0) {
node1 = new GraphNode(node1Name);
index[node1Name] = count++;
g.push_back(node1);
} else {
node1 = g[index[node1Name]];
}
if(index.count(node2Name) == 0) {
node2 = new GraphNode(node2Name);
index[node2Name] = count++;
g.push_back(node2);
} else {
node2 = g[index[node2Name]];
}

node1->addChildren(node2, value1);
node2->addChildren(node1, value2);
}
printG();
len = g.size();
vector<double> res;
for(auto query : queries) {
res.push_back(search(query[0], query[1]));
}
return res;
}

void printG() {
for(auto node : g) {
cout << node->name << ": ";
int size = node->children.size();
for(int i = 0; i < size; i++) {
cout << "(" << node->children[i]->name << " | " << node->values[node->children[i]->name] << "), ";
}
cout << endl;
}

}

double search(const string& s, const string& e) {
// printf("%s -> %s\n", s.c_str(), e.c_str());
if(index.count(e) == 0 || index.count(s) == 0) return -1.0;
int target = index[e];
int start = index[s];
if(start == target) return 1.0;
vector<bool> visited(len, false);
stack<pair<int, double>> q;
q.push(pair<int, double>(start, 1.0));
visited[start] = true;
double res = 1.0;
while(!q.empty()) {
int nodeIndex = q.top().first;
double val = q.top().second;
res *= val;
GraphNode* node = g[nodeIndex];
bool add = false;
// printf("node %s\n", node->name.c_str());
q.pop();
for(GraphNode* child : node->children) {
int childIndex = index[child->name];
if(childIndex == target) {
return res * node->values[child->name];
} else if(!visited[childIndex]) {
q.push(pair<int, double>(childIndex, node->values[child->name]));
visited[childIndex] = true;
add = true;
}
}
if(!add) {
res /= val;
}
}
return -1.0;
}
};

template<class T>
void printVec(const vector<T> &v, const string& head = "")
{
if(head != "") {
cout << head << ": ";
}
for (T i : v)
{
cout << i << " ";
}
cout << "\n";
}
int main() {
Solution s;
vector<vector<string>> equations = {{"a","e"},{"b","e"}};
vector<double> values = {4.0,3.0};
vector<vector<string>> queries = {{"a","b"},{"e","e"},{"x","x"}};
vector<double> res = s.calcEquation(equations, values, queries);
printVec<double>(res, "result = ");
return 0;
}
作者

Meow Meow Liu

发布于

2022-10-05

更新于

2026-10-19

许可协议

评论