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 values are positive. This represents the equations..

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.

Tips:

  • 解法1:

最直白的解法。先过滤掉没有见过的字符,形成字典,然后开始算结果。如果发现问题中设计的两个字串有一个没有出现在字典里,就返回-1,其他情况则进入DFS。

DFS中建立一个新的stack,针对每个queary依次搜索每个equation,如果equation中有queary种两个字串的任意一个,就接着往下搜,temp = helper * value 或 helper / value直到搜出结果。

值得注意的是,这里有 if(temp > 0) return; else stack pop()的语句,是因为题中表示所有等式的值都是positive的,所以如果出现负数,则一定是在这次DFS中直到叶子都没找到结果,返回了-1。所以此时要pop之后接着搜答案。

  • 解法2:

先把所有equation都存进map里,这样在queary大的时候比解法一快。

  • 解法3:并查集

应该就是在找老大哥合并的过程,只是在compress find的时候和union的时候带着value呗~

Code:

解法1:

public class Solution {
    public double[] calcEquation(String[][] equations, double[] values, String[][] query) {
        double[] result = new double[query.length];
        // filter unexpected words
        // 过滤掉没有遇见过的字符
        Set<String> words = new HashSet<>();
        for (String[] strs : equations) {
            words.add(strs[0]);
            words.add(strs[1]);
        }
        for (int i = 0; i < query.length; ++i) {
            String[] keys = query[i];
            if (!words.contains(keys[0]) || !words.contains(keys[1])) result[i] = -1.0d;
            else {
                Stack<Integer> stack = new Stack<>();
                result[i] = helper(equations, values, keys, stack);
            }
        }
        return result;
    }

    public double helper(String[][] equations, double[] values, String[] keys, Stack<Integer> stack) {
        // 直接查找,key的顺序有正反
        // look up equations directly
        for (int i = 0; i < equations.length; ++i) {
            if (equations[i][0].equals(keys[0]) && equations[i][1].equals(keys[1])) return values[i];
            if (equations[i][0].equals(keys[1]) && equations[i][1].equals(keys[0])) return 1 / values[i];
        }
        // lookup equations by other equations
        // 间接查找,key的顺序也有正反
        for (int i = 0; i < equations.length; ++i) {
            if (!stack.contains(i) && keys[0].equals(equations[i][0])) {
                stack.push(i);
                double temp = values[i] * helper(equations, values, new String[]{equations[i][1], keys[1]}, stack);
                if (temp > 0) return temp;
                else stack.pop();
            }
            if (!stack.contains(i) && keys[0].equals(equations[i][1])) {
                stack.push(i);
                double temp = helper(equations, values, new String[]{equations[i][0], keys[1]}, stack) / values[i];
                if (temp > 0) return temp;
                else stack.pop();
            }
        }
        // 查不到,返回-1
        return -1.0d;
    }
}

解法2:

public double[] calcEquation(String[][] equations, double[] values, String[][] query) {
        // use table save string to integer
        Map<String, Integer> table = new HashMap<>();
        int len = 0;
        for (String[] strings : equations)
            for (String string : strings)
                if (!table.containsKey(string)) table.put(string, len++);

        // init map by direct equation
        double[][] map = new double[len][len];
        for (int i = 0; i < len; ++i)
            for (int j = 0; j < len; ++j)
                map[i][j] = (i == j ? 1.0d : -1.0d);
        for (int i = 0; i < equations.length; ++i) {
            String[] keys = equations[i];
            int row = table.get(keys[0]);
            int col = table.get(keys[1]);
            map[row][col] = values[i];
            map[col][row] = 1 / values[i];
        }

        // floyd-warshall like algorithm
        for (int i = 0; i < len; ++i) {
            for (int j = 0; j < len; ++j) {
                for (int k = 0; k < len; ++k) {
                    if (map[j][i] >= 0d && map[i][k] >= 0d) {
                        map[j][k] = map[j][i] * map[i][k];
                        }
                }
            }
        }

        // query now
        double[] result = new double[query.length];
        for (int i = 0; i < query.length; ++i) {
            String[] keys = query[i];
            Integer row = table.get(keys[0]);
            Integer col = table.get(keys[1]);
            if (row == null || col == null) result[i] = -1.0d;
            else result[i] = map[row][col];
        }
        return result;
    }

解法3:

public double[] calcEquation(String[][] equations, double[] values, String[][] query) {

        // map string to integer
        Map<String, Integer> mIdTable = new HashMap<>();
        int len = 0;
        for (String[] words : equations)
            for (String word : words)
                if (!mIdTable.containsKey(word)) mIdTable.put(word, len++);

        // init parent index and value
        Node[] nodes = new Node[len];
        for (int i = 0; i < len; ++i) nodes[i] = new Node(i);

        // union, you can take an example as follows
        // (a/b=3)->(c/d=6)->(b/d=12)
        for (int i = 0; i < equations.length; ++i) {
            String[] keys = equations[i];
            int k1 = mIdTable.get(keys[0]);
            int k2 = mIdTable.get(keys[1]);
            int groupHead1 = find(nodes, k1);
            int groupHead2 = find(nodes, k2);
            nodes[groupHead2].parent = groupHead1;
            nodes[groupHead2].value = nodes[k1].value * values[i] / nodes[k2].value;
        }

        // query now
        double[] result = new double[query.length];
        for (int i = 0; i < query.length; ++i) {
            Integer k1 = mIdTable.get(query[i][0]);
            Integer k2 = mIdTable.get(query[i][1]);
            if (k1 == null || k2 == null) result[i] = -1d;
            else {
                int groupHead1 = find(nodes, k1);
                int groupHead2 = find(nodes, k2);
                if (groupHead1 != groupHead2) result[i] = -1d;
                else result[i] = nodes[k2].value / nodes[k1].value;
            }
        }
        return result;
    }

    public int find(Node[] nodes, int k) {
        int p = k;
        while (nodes[p].parent != p) {
            p = nodes[p].parent;
            // compress
            nodes[k].value *= nodes[p].value;
        }
        // compress
        nodes[k].parent = p;
        return p;
    }

    private static class Node {
        int    parent;
        double value;

        public Node(int index) {
            this.parent = index;
            this.value = 1d;
        }
    }

results matching ""

    No results matching ""