class UnionFind:
def __init__(self, nodes):
self.root = {node : node for node in nodes}
self.rank = {node : 0 for node in nodes}
def find(self, x) -> str:
if x not in self.root:
self.root[x] = x
if x != self.root[x]:
self.root[x] = self.find(self.root[x])
return(self.root[x])
def union(self, x, y):
rootX = self.find(x)
rootY = self.find(y)
if rootX == rootY:
return(False)
if self.rank[rootX] > self.rank[rootY]:
self.root[rootY] = rootX
elif self.rank[rootY] > self.rank[rootX]:
self.root[rootX] = rootY
else:
self.rank[rootX] += 1
self.root[rootY] = rootX
return(True)
def connected(self, x, y):
return(
self.find(x) == self.find(y)
)
class Solution:
def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]:
self.nodes = set()
for idx, eq in enumerate(equations):
self.nodes.add(eq[0])
self.nodes.add(eq[1])
self.graph = defaultdict(list)
self.uf = UnionFind(self.nodes)
for idx, eq in enumerate(equations):
self.graph[eq[0]].append(
(eq[1], float(values[idx]))
)
self.graph[eq[1]].append(
(eq[0], float(1 / values[idx]))
)
self.uf.union(eq[0], eq[1])
resp = []
for query in queries:
resp.append(
self.dfs(query[0], query[1])
)
return(resp)
def dfs(self, num, den):
if not self.uf.connected(num, den) or num not in self.nodes or den not in self.nodes:
return(float(-1))
elif num == den:
return(float(1))
stack = [(num, float(1))]
seen = set()
while stack:
currNode, currVal = stack.pop()
if currNode in seen:
continue
seen.add(currNode)
for neighbor, neighborVal in self.graph[currNode]:
if neighbor in seen:
continue
neighborUpdate = currVal * neighborVal
if neighbor == den:
return(neighborUpdate)
stack.append((neighbor, neighborUpdate))
return(float(-1))