1. 程式人生 > 實用技巧 >399. Evaluate Division

399. Evaluate Division

問題:

給定 一組【被除數,除數,商】的陣列,根據已知的等式關係,

求要求的一組【被除數,除數】的商。

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 , where equations.size() == values.size(), and the values are positive. This represents the equations. Return vector<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"] ]. 

  

解法:並查集(Disjoint Set)

根據給定的【被除數,除數,商】,可以建立【被除數,除數】之間的關係(係數為【商】)

則所有【被除數,除數】對,可以看作兩個頂點的連線。(【商】為兩點連線的係數)

最後所求為,給定兩個點是否有連線,沒有的話,返回-1,否則返回兩點之間的係數【商】。

因此,我們可在原來基礎的Disjoint Set中parent的關係基礎上,增加一個變數,來指示二點之間的關係係數【商】

vector<pair<int, double>> parent;

  • parent[i].first:頂點 i 的父節點
  • parent[i].second:頂點 i 與其父節點的關係係數

-> 頂點 i = parent[i] * 係數

在本問題中,

  1. 由於頂點不確定性,我們不再使用固定長度的parent。而使用動態變化的parent。這裡需要增加,增加節點方法:newpoint
  2. 頂點指示為string型別,因此需要增加對映,unordered_map<string, int> pos;

綜上,我們對本問題經過適用改善的Disjoint Set類變為:

 1 class DisjointSet {
 2 public:
 3     DisjointSet() {}
 4     void newpoint() {
 5         parent.push_back(make_pair(parent.size(), 1.0
)); 6 rank.push_back(0); 7 } 8 pair<int, double> find(int i) { 9 if(parent[i].first != i){ 10 pair<int, double> pa = find(parent[i].first); 11 parent[i].first = pa.first; 12 parent[i].second *= pa.second; 13 } 14 return parent[i]; 15 } 16 bool merge(int x, int y, double val) {//x=y*val 17 pair<int, double> x_root = find(x); 18 pair<int, double> y_root = find(y); 19 if(x_root.first == y_root.first) return false; 20 if(rank[x_root.first] < rank[y_root.first]) { 21 parent[x_root.first].first = y_root.first; 22 parent[x_root.first].second = y_root.second * val; 23 } else if(rank[y_root.first] < rank[x_root.first]) { 24 parent[y_root.first].first = x_root.first; 25 parent[y_root.first].second = x_root.second / val ; 26 } else { 27 parent[x_root.first].first = y_root.first; 28 parent[x_root.first].second = y_root.second * val; 29 rank[y_root.first] ++; 30 } 31 return true; 32 } 33 double getdivideval(int x, int y) { 34 pair<int, double> x_root = find(x); 35 pair<int, double> y_root = find(y); 36 if(x_root.first == y_root.first) return x_root.second/y_root.second; 37 else return -1.0; 38 } 39 private: 40 vector<pair<int, double>> parent; 41 vector<int> rank; 42 };

本問題的解決

程式碼參考:

 1 class Solution {
 2 public:
 3     vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
 4         vector<double> res;
 5         unordered_map<string, int> pos;
 6         DisjointSet DS;
 7         for(int i=0; i<values.size(); i++) {
 8             string a = equations[i][0];
 9             string b = equations[i][1];
10             double val = values[i];
11             if(pos.count(a)==0) {
12                 pos[a] = pos.size();
13                 DS.newpoint();
14             }
15             if(pos.count(b)==0) {
16                 pos[b] = pos.size();
17                 DS.newpoint();
18             }
19             DS.merge(pos[a],pos[b],val);
20         }
21         for(vector<string> q:queries) {
22             if(pos.count(q[0]) == 0 || pos.count(q[1]) == 0) {
23                 res.push_back(-1.0);
24             } else {
25                 res.push_back(DS.getdivideval(pos[q[0]], pos[q[1]]));
26             }
27         }
28         return res;
29     }
30 };