1. 程式人生 > >LeetCode 399. Evaluate Division

LeetCode 399. Evaluate Division

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:

https://leetcode.com/problems/evaluate-division/discuss/88170/0ms-C++-Union-Find-Solution-EASY-to-UNDERSTAND

http://www.cnblogs.com/grandyang/p/5880133.html