LeetCode 399. Evaluate Division - 彻底掌握并查集(Union Find)系列题18

这道LeetCode 399题需要运用并查集解决变量间的比例关系问题。解题关键在于每个集合的节点存储与根节点的比例关系,通过查找和合并操作,能计算出任意两个节点的比例。详细解题思路包括如何定义UnionFind结构、实现查找和合并功能,以及处理比例关系的计算。完成此题将有助于深入理解并查集的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值