Friday, September 23, 2016

Evaluate Division

Equations are given in the format A / B = k, where A and B are variables represented as strings, and k is a real number (floating point number). Given some queries, return the answers. If the answer does not exist, return -1.0.
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"] ]. 
The input is always valid. You may assume that evaluating the queries will result in no division by zero and there is no contradiction.

Analysis:

This is to find if two elements are connected. A typical graph practice.
After a path is found out, the answer to query is multiply of edges:
a/b=1,b/c=2,c/d=3, then a/d = a/b*b/c*c/d=6.0


class Edge{
    String from,to;
    double weight;
public Edge(String a,String b, double w){
    from = a;
    to = b;
    weight = w;
}
public String toString(){
    return from+"->"+to+":"+weight;
}
public int hashCode(){
    return toString().hashCode();
}    
public boolean equals(Object b){
    if(b instanceof Edge && toString().equals(b.toString())){
        return true;
    }
    return false;
}
}
class EdgeWeightedGraph{
    Map<String,Set<Edge>> adj = new HashMap<String,Set<Edge>>();
    
    public void addEdge(String a,String b, double weight){
        Edge one = new Edge(a,b,weight);
        Edge two = new Edge(b,a,1.0/weight);
        if(adj.containsKey(a)){
            adj.get(a).add(one);
        }else{
            Set<Edge> s = new HashSet<Edge>();
            s.add(one);
            adj.put(a,s);
        }
        if(adj.containsKey(b)){
            adj.get(b).add(two);
        }else{
            Set<Edge> s = new HashSet<Edge>();
            s.add(two);
            adj.put(b,s);
        }
    }
    public boolean contains(String a){
        return adj.containsKey(a);
    }
    public List<Edge> getPath(String a, String b){
        Set<Edge> visited = new HashSet<Edge>();
        List<Edge> path = new ArrayList<Edge>();
        path = dfsGetPath(a,b,path,visited);
        return path;
    }
    private List<Edge> dfsGetPath(String start,String end,List<Edge> path,Set<Edge> visited){
        if(start.equals(end)){
            //List<Edge> result = new ArrayList<Edge>();
            //result.addAll(path);
            return path;
        }
        if(adj.get(start)!=null){
            for(Edge e:adj.get(start)){
                if(visited.add(e)){
                    path.add(e);
                    List<Edge> r = dfsGetPath(e.to,end,path,visited);
                    if(r.size()>0){
                        return r;
                        //stop further processing
                    }
                    path.remove(e);//next loop starting from same path path
                }
            }
        }
        return new ArrayList<Edge>();
    }
}
public class Solution {
    public double[] calcEquation(String[][] equations, double[] values, String[][] queries) {
        //prepare
        double[] result = new double[queries.length];
        EdgeWeightedGraph g = new EdgeWeightedGraph();
        for(int i=0;i<values.length;i++){
            g.addEdge(equations[i][0],equations[i][1],values[i]);
        }
        for(int i=0;i<queries.length;i++){
            if(queries[i][0].equals(queries[i][1])&&g.contains(queries[i][0])){
                result[i]=1.0;
                continue;
            }
            List<Edge> r = g.getPath(queries[i][0],queries[i][1]);
            if(r.size()==0){
                result[i]=-1.0;
            }else{
                result[i]=1;
                for(Edge e:r){
                    result[i]*=e.weight;
                }
            }
        }
        return result;
    }
}

No comments: