LeetCode Top 100 Liked Questions 399. Evaluate Division (Java版; Medium)

welcome to my blog

LeetCode Top 100 Liked Questions 399. Evaluate Division (Java版; Medium)

题目描述
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"] ]. 
第一次做; 改写了最优解的结构, 个人感觉改写后的并查集结构更加清晰简单, 最优解稍微有些耦合, 属于高手的范畴; 这题是真的难
/*
并查集
核心:1.定义节点的父, 2.a/b不是通过a和b的关系计算, 而是通过a的父和b的父进行计算
*/
class Solution {
    public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
        double[] res = new double[queries.size()];
        //并查集
        Map<String, String> fatherMap = new HashMap<>();
        Map<String, Double> aboutFatherFactorMap = new HashMap<>();
        //初始化; 每个人的掌门都是自己
        for(int i=0; i<equations.size(); i++){
            String first = equations.get(i).get(0);
            String second = equations.get(i).get(1);
            if(!fatherMap.containsKey(first)){
                fatherMap.put(first, first);
                aboutFatherFactorMap.put(first, 1.0);
            }
                
            if(!fatherMap.containsKey(second)){
                fatherMap.put(second, second);
                aboutFatherFactorMap.put(second, 1.0);
            }
        }
        /*
        equations中会出现first的新掌门--second, 接下来让first的老掌门加入到新掌门下
        我最开始接触的union操作是门派人数的少加入门派人数多的, 这里不一样, 这里是让旧的加入新的
        */
        //union操作; 让first的掌门加入second的掌门
        for(int i=0; i<equations.size(); i++){
            String first = equations.get(i).get(0);
            String second = equations.get(i).get(1);
            
            String father1 = findFather(fatherMap, aboutFatherFactorMap, first);
            String father2 = findFather(fatherMap, aboutFatherFactorMap, second);
            //核心:让first的掌门加入second的掌门
            fatherMap.put(father1, father2);
            //核心: 更新father1的aboutFatherFactor
            aboutFatherFactorMap.put(father1, aboutFatherFactorMap.get(second) * values[i] / aboutFatherFactorMap.get(first));
        }
        //至此, 并查集操作结束, 涉及两个操作: 1)初始化 2)union
        
        //执行查询
        for(int i=0; i<queries.size(); i++){
            String first = queries.get(i).get(0);
            String second = queries.get(i).get(1);
            if(!fatherMap.containsKey(first) || !fatherMap.containsKey(second))
                res[i] = -1.0;
            //当first和seconde都存在时
            else{
                String father1 = findFather(fatherMap, aboutFatherFactorMap, first);
                String father2 = findFather(fatherMap, aboutFatherFactorMap, second);
                //如果father1和father2不同, 说明,first/second没有答案
                if(!father1.equals(father2))
                    res[i] = -1.0;
                else{
                    //核心
                    res[i] = (double)aboutFatherFactorMap.get(first) / aboutFatherFactorMap.get(second);
                }
            }
        }
        return res;
    }
    public String findFather(Map<String, String> fatherMap, Map<String, Double> aboutFatherFactorMap, String curr){
        String father = fatherMap.get(curr);
        //base case
        if(curr.equals(father))
            return curr;
        String oldFather = father;
        father = findFather(fatherMap, aboutFatherFactorMap, father);
        fatherMap.put(curr, father); //这一步很有路径压缩的感觉
        //核心
        aboutFatherFactorMap.put(curr, aboutFatherFactorMap.get(curr) * aboutFatherFactorMap.get(oldFather));
        return father;
    }
}
LeetCode最优解; 并查集
1. Thoughts
    - check if we have enough info to get the result
    - if yes, calculate; if not, return -1.0
    - Method: union find
        - a/b = 2.0 --> b is the root of a; the distance from a to b is 1/2.0
        - if two nums have the same root, we can get the result; a/b=2.0, b/c=3.0
        index   a   b   c
        root    b   c   c 
        dist    2   3   1
        - if we want to know a/c = ?: a = 2 * b = 2 * 3 * c => a/c = 6.0
2. Corner case
    - if any input is null, return null
    - no enough info, return -1.0
3. Steps
    - go through equations to union elements with the same root and update root map and distance map
    - go through each query: check if has the same root; find relative dist
class Solution {
    public double[] calcEquation(String[][] e, double[] values, String[][] q) {
        double[] res = new double[q.length];
        Map<String, String> root = new HashMap<>();
        Map<String, Double> dist = new HashMap<>();
        for (int i = 0; i < e.length; i++) {
            String r1 = find(root, dist, e[i][0]);
            String r2 = find(root, dist, e[i][1]);
            root.put(r1, r2);
            dist.put(r1, dist.get(e[i][1]) * values[i] / dist.get(e[i][0]));
        }
        for (int i = 0; i < q.length; i++) {
            if (!root.containsKey(q[i][0]) || !root.containsKey(q[i][1])) {
                res[i] = -1.0;
                continue;
            }
            String r1 = find(root, dist, q[i][0]);
            String r2 = find(root, dist, q[i][1]);
            if (!r1.equals(r2)) {
                res[i] = -1.0;
                continue;
            }
            res[i] = (double) dist.get(q[i][0]) / dist.get(q[i][1]);
        }
        return res;
    }
    
    private String find(Map<String, String> root, Map<String, Double> dist, String s) {
        if (!root.containsKey(s)) {
            root.put(s, s);
            dist.put(s, 1.0);
            return s;
        }
        if (root.get(s).equals(s)) return s;
        String lastP = root.get(s);
        String p = find(root, dist, lastP);
        root.put(s, p);
        dist.put(s, dist.get(s) * dist.get(lastP));
        return p;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值