leetcode 除法求值

给出方程式 A / B = k, 其中 A 和 B 均为用字符串表示的变量, k 是一个浮点型数字。根据已知方程式求解问题,并返回计算结果。如果结果不存在,则返回 -1.0。

示例 :
给定 a / b = 2.0, b / c = 3.0
问题: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ?
返回 [6.0, 0.5, -1.0, 1.0, -1.0 ]

输入为: vector> equations, vector& values, vector> queries(方程式,方程式结果,问题方程式), 其中 equations.size() == values.size(),即方程式的长度与方程式结果长度相等(程式与结果一一对应),并且结果值均为正数。以上为方程式的描述。 返回vector类型。

基于上述例子,输入如下:

equations(方程式) = [ ["a", "b"], ["b", "c"] ],
values(方程式结果) = [2.0, 3.0],
queries(问题方程式) = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ].
输入总是有效的。你可以假设除法运算中不会出现除数为0的情况,且不存在任何矛盾的结果。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/evaluate-division

AC代码

Map>> map;

/**
 * 计算结果
 * @param equations 方程式
 * @param values 方程式结果
 * @param queries 问题方程式
 * @return 计算结果
 */
public double[] calcEquation(List> equations, double[] values, List> queries) {
    // 注: a ÷ b = c中,a为被除数,b为除数,c为商

    // map的key为除数,value为Set
    // pair中,key为被除数,value为商
    // 比如a÷b=2, b÷c=3,则map的内容为:
    // map.put(b, [])
    // map.put(c, [, ])
    map = new HashMap<>(equations.size());

    // 存所有的被除数和除数
    Set allNum = new HashSet<>(equations.size());

    for (int i = 0; i < equations.size(); i++) {
        List equation = equations.get(i);
        // 被除数
        String dividend = equation.get(0);
        // 除数
        String divisor = equation.get(1);

        // 构造map
        buildMap(dividend, divisor, values[i]);
        // 交换被除数和除数,再次构造map
        buildMap(divisor, dividend, 1 / values[i]);

        allNum.add(dividend);
        allNum.add(divisor);
    }


    // 结果集
    double[] results = new double[queries.size()];
    // 结果不存在,则返回 -1.0
    double noResult = -1.0;

    // 遍历问题方程式
    for (int i = 0; i < queries.size(); i++) {
        List query = queries.get(i);
        String dividend = query.get(0);
        String divisor = query.get(1);

        // 被除数或除数在equations中不曾出现过
        if (!(allNum.contains(dividend) && allNum.contains(divisor))) {
            results[i] = noResult;
            continue;
        }
        // 被除数与除数相等
        if (Objects.equals(dividend, divisor)) {
            results[i] = 1;
            continue;
        }

        Double result = calculate(dividend, divisor);
        results[i] = null == result ? noResult : result;
    }

    return results;
}

/**
 * 构造map
 * @param dividend 被除数
 * @param divisor 除数
 * @value value 商
 */
private void buildMap(String dividend, String divisor, Double value) {
    // 被除数等于除数,或者map中已存在,退出方法
    if (dividend.equals(divisor) || exist(dividend, divisor)) {
        return;
    }

    // key为被除数,value为商
    Pair pair = new Pair(dividend, value);

    Set> pairs = null;
    if (map.containsKey(divisor)) {
        pairs = map.get(divisor);
        pairs.add(pair);
    } else {
        pairs = new HashSet<>();
        pairs.add(pair);
        map.put(divisor, pairs);
    }

    List> triples = new ArrayList<>();

    // 如果被除数有被除数
    if (map.containsKey(dividend)) {
        // 被除数的被除数集合
        Set> pairsForDividend = map.get(dividend);
        for (Pair pairForDividend: pairsForDividend) {
            String pairKey = pairForDividend.getKey();
            Double pairValue = pairForDividend.getValue();
            pairs.add(new Pair(pairKey, pairValue * value));
            if (!exist(divisor, pairKey)) {
                triples.add(new Triple(divisor, pairKey, 1 / (pairValue * value)));
            }
        }
    }

    // 直接在for循环里递归buildMap可能有并发修改map的风险,因此提到外面
    // 交换被除数和除数,再次构造map
    for (Triple triple: triples) {
        buildMap(triple.left, triple.middle, triple.right);
    }
}

/**
 * 根据被除数和除数计算结果
 * @param dividend 被除数
 * @param divisor 除数
 * @return 计算结果
 */
private Double calculate(String dividend, String divisor) {
    Set> pairs = map.get(divisor);
    if (null == pairs) {
        return null;
    }
    for (Pair pair: pairs) {
        if (pair.getKey().equals(dividend)) {
            return pair.getValue();
        }
    }
    return null;
}

/**
 * 判断map中是否已存在重复数据
 * 注意: 比较被除数和除数即可,不用比较商,会有浮点数精度问题
 * @param dividend 被除数
 * @param divisor 除数
 * @return 是否已存在
 */
private boolean exist(String dividend, String divisor) {
    Set> pairs = map.get(divisor);
    if (null == pairs) {
        return false;
    }
    for (Pair pair: pairs) {
        if (pair.getKey().equals(dividend)) {
            return true;
        }
    }
    return false;
}

class Triple {
    private L left;
    private M middle;
    private R right;

    public Triple(L left, M middle, R right) {
        this.left = left;
        this.middle = middle;
        this.right = right;
    }
}


image.png


另一个思路

以a / b = 2, b / c = 3为例,步骤如下:
1.拿到第一个方程式时,把除数初始化为1,即把b初始化为1,然后把a初始化为2
2.维护一个队列queue,把a和b放进队列
3.while(!queue.isEmpty()),while循环中,每次拿出queue的一个值x,遍历所有方程式,如果可以利用x算出另一个变量,就把新算出的变量放进queue
4.重复步骤3,直到while退出,即所有可求出值的变量都使用过

你可能感兴趣的:(leetcode 除法求值)