中级农民
- 积分
- 217
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2017-11-30
- 最后登录
- 1970-1-1
|
399. Evaluate Division
1. Understand problem at 1 min
2. Get key concept at 7 min
3. Algorithm draft at 8 min
4. Detailed example derivation
5. Code draft at 53 min
6. Code compile at 54 min (only ONE syntax error in 170 lines of code)
7. AC solution at 61 min (found one semantic error)
狗家经典题,知识点如下:
1. 有向图遍历
2. find path between node A and B (BFS/DFS)
3. memoization basics
C++代码量太大了,170行,可读性没问题,但是太长了写不完,这是问题。不过通过最近写几个150行上下的题目,感觉对C++语法愈加熟练,这次170行代码从头到尾只有一个syntax error (typo) 和一个semantic error,而且非常容易debug。
C++ 代码如下:
class Solution {
public:
vector<double> calcEquation(vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries) {
/* First, build the graph */
/* This is a directed graph, but each edge exist in both ways (with its value inverted) */
/* a/b:a->b, b/c: b->c, a/c: a/b * b/c a->b->c */
/* This is a graph search problem, my target is find if there is a directed path from A to B */
/* The key clean coding using Given API */
/* Algorithm:
1. Build a graph using inputs
2. Write a modular BFS function for node search
3. Before each search, do a sanity check (a/a, x/x, a/e)
4. Repeatedly call BFS to fill answer query
*/
/* 1. prep */
vector<double> answerStore;
if(equations.size() != values.size()){
return answerStore;
}
/* 2. key algorithms */
/* build graph */
unordered_map<string, unordered_map<string, double> > graph = BuildGraph(equations, values);
unordered_map<string, double> doneAnswers; /* memorize the result for quick lookup*/
/* BFS calls (do sanity check for every query) */
for(auto query : queries){
string fromNode = query.first, toNode = query.second;
/* check for existing answers */
string pathCode = fromNode + " " + toNode;
if(doneAnswers.find(pathCode) != doneAnswers.end()){
answerStore.emplace_back(doneAnswers[pathCode]);
continue;
}
/* calculate (heavy lifting) */
double ansVal = findPath(graph, fromNode, toNode);
/* store to answerStore */
answerStore.emplace_back(ansVal);
/* memorize answer */
double invertVal = 1 / ansVal;
string invertCode = toNode + " " + fromNode;
doneAnswers[pathCode] = ansVal;
doneAnswers[invertCode] = invertVal;
}
/* 3. answer */
return answerStore;
}
/* need to record path */
double findPath(const unordered_map<string, unordered_map<string, double> > & graph,
const string & fromNode, const string & toNode){
/* bfs, record path */
/* 0. MISC*/
/* sanity check */
/* doesn't exist */
if(graph.find(fromNode) == graph.end() || graph.find(toNode) == graph.end()){
return -1.0;
}
/* divide self */
if(fromNode == toNode){
return 1.0;
}
/* 1. prep */
unordered_map<string, pair<string, double> > trackBack;
unordered_set<string> visited;
queue<string> bfsQueue;
bfsQueue.emplace(fromNode);
visited.emplace(fromNode);
/* 2. key algorithm */
/* BFS */
bool found = false;
while(!bfsQueue.empty() && !found){
string node = bfsQueue.front();
bfsQueue.pop();
unordered_map<string, double> edges = graph.find(node)->second;
for(auto edgeItr = edges.begin(); edgeItr != edges.end(); ++edgeItr){
string dstName = edgeItr->first;
double dstValue = edgeItr->second;
if(visited.find(dstName) != visited.end()){
continue;
}
visited.emplace(dstName);
trackBack[dstName] = {node, dstValue}; /* this values are the invert of actual edge values */
if(dstName == toNode){
found = true;
}
bfsQueue.push(dstName);
}
}
if(!found){
return -1.0;
}
/* track back */
double answer = 1.0;
string target = fromNode;
string current = toNode;
while(current != fromNode){
answer *= trackBack[current].second;
current = trackBack[current].first;
}
/* 3. return answer */
return answer;
}
unordered_map<string, unordered_map<string, double> >
BuildGraph(const vector<pair<string, string>> & equations, const vector<double>& values){
/* every single equation represents a both-way edge with inverted values */
/* the finished graph should contain all possible values as keys; this fact can be used for sanity check */
/* 1. prep */
unordered_map<string, unordered_map<string, double> > graph;
/* 2. key algroithm */
for(int i = 0; i < equations.size(); ++i){
string fromNode = equations[i].first, toNode = equations[i].second;
double forwardValue = values[i], backwardValue = 1/forwardValue;
if(graph.find(fromNode) == graph.end()){
graph[fromNode] = unordered_map<string, double>();
}
graph[fromNode][toNode] = forwardValue;
if(graph.find(toNode) == graph.end()){
graph[toNode] = unordered_map<string, double>();
}
graph[toNode][fromNode] = backwardValue;
}
# if 0
/* debug print start */
PrintGraph(graph);
/* debug end */
#endif
/* 3. answer */
return graph;
}
void PrintGraph(const unordered_map<string, unordered_map<string, double> > & graph){
for(auto itr = graph.begin(); itr != graph.end(); ++itr){
cout << itr->first << " : ";
unordered_map<string, double> edges = itr->second;
for(auto toItr = edges.begin(); toItr != edges.end(); ++toItr){
cout << toItr->first << " " << toItr->second << " | ";
}
cout << endl;
}
}
}; |
|