跳到主要内容

399. 除法求值

题目描述

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

给定一个查询数组 queries,其中 queries[j] = [Cj, Dj] 表示第 j 个查询。求解 Cj / Dj = ?

如果不存在确定的答案,返回 -1.0

示例

示例 1:

输入:equations = [["a","b"],["b","c"]], values = [2.0,3.0],
queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
输出:[6.0, 0.5, -1.0, 1.0, -1.0]

解题思路

第一步:理解问题本质

把每个变量看作图中的节点,等式看作带权边。a / b = 2 表示从 ab 有一条权值为 2 的边。

查询 a / c 等价于找从 ac 的路径上所有权值的乘积。

第二步:DFS/BFS 解法

对每个查询,从起点开始做 DFS/BFS,找到达终点的路径,计算路径权值乘积。

缺点:每次查询都需要重新搜索,效率低。

第三步:并查集解法(最优)

核心洞察

  • 并查集可以维护节点的连通性
  • 带权并查集额外维护每个节点到根节点的权重
  • 路径压缩时同步更新权重

完整代码实现

from typing import List


class UnionFind:
"""带权并查集"""

def __init__(self, n: int):
self.parent = [i for i in range(n)]
self.weight = [1.0] * n # weight[i] = i / parent[i]

def find(self, x: int) -> int:
if x != self.parent[x]:
origin = self.parent[x]
self.parent[x] = self.find(self.parent[x])
self.weight[x] *= self.weight[origin]
return self.parent[x]

def union(self, x: int, y: int, value: float) -> None:
"""合并,已知 x / y = value"""
rootX = self.find(x)
rootY = self.find(y)
if rootX == rootY:
return

self.parent[rootX] = rootY
# weight[rootX] * weight[x] = value * weight[y]
# => weight[rootX] = value * weight[y] / weight[x]
self.weight[rootX] = self.weight[y] * value / self.weight[x]

def is_connected(self, x: int, y: int) -> float:
rootX = self.find(x)
rootY = self.find(y)
if rootX == rootY:
return self.weight[x] / self.weight[y]
return -1.0


class Solution:
"""
除法求值 - 并查集

时间复杂度:O((E + Q) * alpha(N))
空间复杂度:O(N)
"""

def calcEquation(self, equations: List[List[str]], values: List[float],
queries: List[List[str]]) -> List[float]:
n = len(equations)
uf = UnionFind(2 * n)

# 变量映射到 id
id_map = {}
id_counter = 0

for (a, b), val in zip(equations, values):
if a not in id_map:
id_map[a] = id_counter
id_counter += 1
if b not in id_map:
id_map[b] = id_counter
id_counter += 1
uf.union(id_map[a], id_map[b], val)

# 处理查询
res = []
for a, b in queries:
if a not in id_map or b not in id_map:
res.append(-1.0)
else:
res.append(uf.is_connected(id_map[a], id_map[b]))
return res

示例推演

equations = [["a","b"],["b","c"]], values = [2.0,3.0] 为例:

构建并查集

步骤操作parentweight
初始-[0,1,2,3][1,1,1,1]
1union(a,b,2)[1,1,2,3][2,1,1,1]
2union(b,c,3)[1,2,2,3][2,3,1,1]

查询 a / c

  • find(a): parent[a]=1, weight[a]=2; parent[1]=2, weight[1]=3
  • 路径压缩后:parent[a]=2, weight[a]=2*3=6
  • find(c): parent[c]=2, weight[c]=1
  • a / c = weight[a] / weight[c] = 6 / 1 = 6.0

复杂度分析

解法时间复杂度空间复杂度说明
DFS/BFSO(Q * (V + E))O(V + E)每次查询搜索
并查集(最优)O((E+Q) * alpha(N))O(N)近乎常数

易错点总结

1. 并查集权重更新

路径压缩时,需要同步更新 weightself.weight[x] *= self.weight[origin]

2. union 时的权重推导

weight[rootX] = value * weight[y] / weight[x],需要仔细推导。


相关题目

加载评论中...