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

猜你喜欢

转载自www.cnblogs.com/hankunyan/p/9950167.html
今日推荐