leetcode hot100之除法求值(399)解析

149 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第23天,点击查看活动详情


前言

  • leetcode hot100,是大厂面试高频题,也是必刷算法题。精选了100道LeetCode上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,按照官方说的,熟练掌握这 100 道题,就具备了代码世界通行的基本能力。

leetcode399题(除法求值)

本文来讲hot100第399题# 除法求值,本题有多种解法,图、二维数组 + 哈希表、并查集,掌握一种即可。

[["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]

给你一个变量对数组 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 的情况,且不存在任何矛盾的结果。

示例:

输入: 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 ]

提示:

  • 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 由小写英文字母与数字组成

分析

  • 题目很长,先把题目意思分析出来,我们由题目可知values[i] = Ai / Bi,这里的Ai/Bi是equations中的每一项的第一位和第二位

  • queries[j] = [Cj,Dj], 然后根据上面的条件求Cj / Dj

  • 无法确定答案或给定了已知条件中没有出现的字符串,返回-1.0

  • 再看例子

equations = [["a","b"],["b","c"]]
values = [2.0,3.0]
queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
  • a / b = 2, b / c = 3,a是b的两倍,b是c的三倍,所以a是c的 2 * 3 = 6倍
  • 所以queries: [a/c = 6.0, b / 2 = 0.5, a / e = -1.0, a/a = 1, x/x = -1.0]

思路

  • 先介绍下图算法:
    • 图算法指利用特制的线条算图求得答案的一种简便算法。无向图、有向图和网络能运用很多常用的图算法,这些算法包括:各种遍历算法(这些遍历类似于树的遍历),寻找最短路径的算法,寻找网络中最低代价路径的算法,回答一些简单相关问题(例如,图是否是连通的,图中两个顶点间的最短路径是什么,等等)的算法。图算法可应用到多种场合,例如:优化管道、路由表、快递服务、通信网站等。
  • 我们创建一个变量名为grah的二维数组,表示图,grah[x][y]表示x / y的商
  • 由例子可知,因为grah[a][b] = 2, 所以grah[b][a] = 1 / 2, 因为grah[b][c] = 3, 所以grah[c][b] = 1 / 3
  • 我们的题目要求queries,所以此例子我们唯一不知道的就是grah[c][a]
  • 根据图算法,因为我们知道a和bb和c的关系,所以求c-a只要累乘c-b-a即可,C → B → A = grah[c][b] * grah[b][a] = 1 / 3 * 1 / 2 = 1 / 6

代码

var calcEquation = function (equations, values, queries) {
  const grah = Object.create(null)
  // 第一步,我们需要存储已知节点的路径值
  for (let i = 0; i < values.length; i++) {
    const x = equations[i][0], y = [equations[i][1]], value = values[i]
    if (!grah[x]) grah[x] = Object.create(null)
    grah[x][y] = value
    if (!grah[y]) grah[y] = Object.create(null)
    grah[y][x] = 1 / value
  }

  // 第二步,通过已知路径,求值
  const visited = new Set()
  const getVal = ([x, y]) => {
    // 未找到x值 返回-1
    if (!grah[x]) return -1
    // 找到对应路径,返回目标结果
    if (grah[x][y]) return grah[x][y]
    // 找到x值,然后我们遍历查找路径,比如c-a,我们就找c-b-a
    // 获取grah[x]所有的值
    let kList = Object.keys(grah[x]), i = -1
    // 遍历当前x对应的所有k,也就是当前节点对应的所有有值的节点
    while (++i < kList.length) {
      const k = kList[i]
      // 使用set,防止我们重复查找
      if (!visited.has(k)) {
        visited.add(k)
        // 查找grah[k, y]的值
        const t = getVal([k, y])
        visited.delete(k)
        // 累乘
        if (t !== -1) return grah[x][k] * t
      }
    }
    // 之前没有return, 说明y也没有找到
    return - 1
  }

  return queries.map(item => getVal(item))
};

结语

  • 本题有多种解法,图、二维数组 + 哈希表、并查集,掌握一种即可,本文主要是图算法的应用,需要有一些图算法的基础。