LeetCode 399. Evaluate Division
阿新 • • 發佈:2018-11-13
Graph+BFS/DFS
這道題最好想到的就是建立一個graph,兩個節點的ratio就當做圖的邊儲存下來。
query的時候,只要從一個節點開始,dfs或者bfs,把一路的ratio都乘起來即可。
用BFS來做:
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>> graph; for (int i=0;i<equations.size();++i){ string a=equations[i].first, b=equations[i].second; graph[a][b] = values[i]; graph[b][a] = 1.0/values[i]; graph[a][a] = 1.0; graph[b][b]= 1.0; } vector<double> res; for (auto query:queries){ string a=query.first, b=query.second; if (!graph.count(a) || !graph.count(b)){ res.push_back(-1.0); continue; } queue<pair<string,double>> q; // <curNode, product so far> unordered_set<string> used({a}); bool find=false; q.push({a,1.0}); while (!q.empty()){ auto cur=q.front(); q.pop(); if (cur.first==b){ res.push_back(cur.second); find = true; break; } for (pair<string,double> x:graph[cur.first]){ if (!used.count(x.first)){ used.insert(x.first); x.second *= cur.second; q.push(x); } } } if (!find) res.push_back(-1.0); } return res; } };
Union Find
用圖來做,既需要大量空間,而且dfs和bfs的效率都不是很高。
這道題也可以用Union Find來做,有關聯的字串就union在一起。每次union的時候,以root為基準,更新節點的值。
本題的關鍵是,當兩個節點都已經存在時,這兩個節點可能在不同的set裡。為了保證 node1->val / node2->val = values[i],我們是要對一邊的集合進行改動的。
假定把 root1 接到 root2 上,root2作為新的root,我們需要對 node1 所在的set裡所有元素進行縮放,這個比例可以很簡單計算出來:
double ratio = value * node2->val / node1->val;
相比graph,這種方法query很方便。如果不在一個set中,直接返回-1。在的話,直接兩個節點的val相除即可,因為val都是相對root的。
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=0;i<equations.size();++i){ string s1=equations[i].first, s2=equations[i].second; if (!m.count(s1) && !m.count(s2)){ m[s1] = new Node(values[i]); m[s2] = new Node(1.0); m[s1]->parent = m[s2]; }else if (!m.count(s1)){ // s2 exists m[s1] = new Node(m[s2]->val*values[i]); m[s1]->parent = m[s2]; }else if (!m.count(s2)){ // s1 exists m[s2] = new Node(m[s1]->val/values[i]); m[s2]->parent = m[s1]; }else{ unionSet(s1,s2,values[i]); } } for (auto query:queries){ string s1=query.first, s2=query.second; if (!m.count(s1) || !m.count(s2) || findSet(m[s1])!=findSet(m[s2])) res.push_back(-1.0); else{ res.push_back( m[s1]->val / m[s2]->val ); } } return res; } private: struct Node{ // for convenience, rank is not included double val; Node *parent; Node(double v):val(v),parent(this){} }; unordered_map<string, Node *> m; //node->val to Node * void unionSet(string s1, string s2, double value){ Node *node1=m[s1], *node2=m[s2]; Node *root1=findSet(node1), *root2=findSet(node2); double ratio = value * node2->val / node1->val; for (auto it=m.begin();it!=m.end();++it) if (findSet(it->second)==root1) it->second->val *= ratio; root1->parent = root2; } Node *findSet(Node *node){ if (node->parent==node) return node; node->parent = findSet(node->parent); return node->parent; } };
References: