You are given an array of variable pairs equations
and an array of real numbers values
, where equations[i] = [Ai, Bi]
and values[i]
represent the equation Ai / Bi = values[i]
. Each Ai
or Bi
is a string that represents a single variable.
You are also given some queries
, where queries[j] = [Cj, Dj]
represents the jth
query where you must find the answer for Cj / Dj = ?
.
Return the answers to all queries. If a single answer cannot be determined, return -1.0
.
Note: The input is always valid. You may assume that evaluating the queries will not result in division by zero and that there is no contradiction.
Example 1:
Input: equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]] Output: [6.00000,0.50000,-1.00000,1.00000,-1.00000] Explanation: 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 ]
Example 2:
Input: equations = [["a","b"],["b","c"],["bc","cd"]], values = [1.5,2.5,5.0], queries = [["a","c"],["c","b"],["bc","cd"],["cd","bc"]] Output: [3.75000,0.40000,5.00000,0.20000]
Example 3:
Input: equations = [["a","b"]], values = [0.5], queries = [["a","b"],["b","a"],["a","c"],["x","y"]] Output: [0.50000,2.00000,-1.00000,-1.00000]
Constraints:
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
consist of lower case English letters and digits.
这道题在并查集Union Find系列里算是比较难的一道题。 因为不仅要把有关系的变量合并到一个集合里,还得知道各个变量之间的比例关系。刷完这题,基本上可以彻底掌握并查集Union Find了。
解题思路:
我们知道在并查集数据结构里的每个集合都有一个根节点,如果我们存下了每个节点跟根节点的比例关系,那就可以算出集合里的任意两个点相除的值。
1)定义UnionFind数据结构,对于一个节点,除了要存储其父节点还需要存储它们的比例关系。
如果是一个新节点a,父节点是其自身,比例关系为1:parent[a] = (a, 1.0)
如果一节点a与其父节点b的关系是a/b = v, 则parent[a] = (b, v)
2) 查找函数,查找一个节点的根父节点,需要返回根父节点以及比例关系。由于每个父节点都有对应的比例值,因此一个节点跟根节点的比例关系就是每一层的父节点的比例值的乘积。
比如parent[a] = (b, v1), parent[b] = (c, v2), parent[c] = (c, 1.0), 查找节点a的根节点返回值为(c, v1 * v2),即a = (v1 * v2) * c
3) 合并函数,如果两个节点已经同属一个集合则不需要合并;否则合并它们的根节点,合并时需要计算两个根节点的比例关系。
比如要合并节点a和b(a/b=v), 它们的根节点分别为(c, v1)和(d, v2),即a = v1 * c, b = v2 * d, 则c / d= (v * v2) / v1, 即parent[c] = (d, v * v2 / v1)。
class UnionFind:
def __init__(self):
self.parent = {}
def find(self, s):
if s not in self.parent:
return ('', -1.0)
if self.parent[s][0] != s:
(p, v) = self.find(self.parent[s][0])
self.parent[s] = (p, v * self.parent[s][1])
return self.parent[s]
def merge(self, s1, s2, v):
[p1,v1] = self.find(s1)
[p2,v2] = self.find(s2)
if p1 == p2:
return
self.parent[p1] = (p2, v * v2 / v1)
def update(self, s):
if s not in self.parent:
self.parent[s] = (s, 1.0)
class Solution:
def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]:
uf = UnionFind()
for i in range(len(equations)):
s1, s2 = equations[i][0], equations[i][1]
uf.update(s1)
uf.update(s2)
uf.merge(s1, s2, values[i])
res = []
for q in queries:
p1, v1 = uf.find(q[0])
p2, v2 = uf.find(q[1])
if p1 != p2 or v1 == -1.0 or v2 == -1.0:
res.append(-1.0)
else:
res.append(v1 / v2)
return res