【LeetCode】399. 除法求值

104 阅读1分钟

「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」。

题目

给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。

另有一些以数组 queries 表示的问题,其中 queries[j] = [Cj, Dj] 表示第 j 个问题,请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。

返回 所有问题的答案 。如果存在某个无法确定的答案,则用 -1.0 替代这个答案。如果问题中出现了给定的已知条件中没有出现的字符串,也需要用 -1.0 替代这个答案。

注意:输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。

示例 1

输入:equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
输出:[6.00000,0.50000,-1.00000,1.00000,-1.00000]
解释:
条件: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 ]

示例 2

输入:equations = [["a","b"],["b","c"],["bc","cd"]], values = [1.5,2.5,5.0], queries = [["a","c"],["c","b"],["bc","cd"],["cd","bc"]]
输出:[3.75000,0.40000,5.00000,0.20000]

示例 3

输入:equations = [["a","b"]], values = [0.5], queries = [["a","b"],["b","a"],["a","c"],["x","y"]]
输出:[0.50000,2.00000,-1.00000,-1.00000]

提示

  • 1 <= equations.length <= 20
  • equations[i].length == 2
  • 1 <= Ai.length, Bi.length <= 5
  • values.length == equations.length
  • 0.0 < values[i] <= 20.0
  • 1 <= queries.length <= 20
  • queries[i].length == 2
  • 1 <= Cj.length, Dj.length <= 5
  • Ai, Bi, Cj, Dj 由小写英文字母与数字组成

题解

思路

除法求值这道问题,刚开始看到这道题,从人的思维来看的话,很想小学时期做的那些等值代换的问题,给你一些值变量值的关系,最后抛出一个全新的式子,利用之前给出的关系式求出未知式子的答案。而本题与之的唯一的区别就是我们要转变人的思维而编程计算机的思维,用代码写出这种问题的解法。

答案正是来源于这样的思维,我们知道,我们是提交代码不是提交自己脑子想的哪些东西,正因如此,需要我上面所说的思维的转变,而要想转变到计算机思维上去最关键的是什么呢?我们思考如何刻画出题目给出的这些关系,其实无非就是告诉你 a 和 b、b 和 c 的关系,然后求出 a 和 c 的关系呗,告诉的是两者之间的关系,对应到计算机抽象思维中是什么,就是图!

两者之间的关系不就是两个节点之间的连接嘛,如果是简单的对等关系,就是无权图,如果有指向性要求,那就是有向无权图,如果不是简单的对等关系,有类似本题的这样的关系,那不就是带权图吗。好了,第一个问题解决了,刻画所给关系就是建图,那第二个问题怎么解决呢?其实也很简单,既然图都建好了,那图中所用的那些方法无非就是 DFS、BFS 这些,而寻找新的对应关系刚好就映射了图的搜索问题。好了,这个问题已经解决了,其实这个问题的难度根本不在所讨论的什么各种方法之间的难度,难就难在把这个图有条有序地建立起来,这个图合适地构建出来了,什么深度优先、广度优先、Floyd、带权并查集的解法就可以一笔带过了。

OK,分析完后,这题使用广度优先搜索解决下:

代码

func calcEquation(equations [][]string, values []float64, queries [][]string) []float64 {
    id := map[string]int{}
    for _, eq := range equations {
        a, b := eq[0], eq[1]
        if _, has := id[a]; !has {
            id[a] = len(id)
        }
        if _, has := id[b]; !has {
            id[b] = len(id)
        }
    }

    type edge struct {
        to     int
        weight float64
    }
    graph := make([][]edge, len(id))
    for i, eq := range equations {
        v, w := id[eq[0]], id[eq[1]]
        graph[v] = append(graph[v], edge{w, values[i]})
        graph[w] = append(graph[w], edge{v, 1 / values[i]})
    }

    bfs := func(start, end int) float64 {
        ratios := make([]float64, len(graph))
        ratios[start] = 1
        queue := []int{start}
        for len(queue) > 0 {
            v := queue[0]
            queue = queue[1:]
            if v == end {
                return ratios[v]
            }
            for _, e := range graph[v] {
                if w := e.to; ratios[w] == 0 {
                    ratios[w] = ratios[v] * e.weight
                    queue = append(queue, w)
                }
            }
        }
        return -1
    }

    ans := make([]float64, len(queries))
    for i, q := range queries {
        start, hasS := id[q[0]]
        end, hasE := id[q[1]]
        if !hasS || !hasE {
            ans[i] = -1
        } else {
            ans[i] = bfs(start, end)
        }
    }
    return ans
}

结语

业精于勤,荒于嬉;行成于思,毁于随。