返回

LeetCode 2003. 每棵子树内缺失的最小基因值:高能解析缺失基因

后端

破解 LeetCode 难题:每棵子树内缺失的最小基因值

在 LeetCode 的浩瀚题海中,2003. 每棵子树内缺失的最小基因值 是一颗璀璨的明珠,它考验着程序员的数据结构和算法基础,以及逻辑思维能力。本文将深入剖析这道困难难题,为你提供清晰易懂的解题思路和代码实现。

一、问题背景

在给定一棵根节点为 0 的家族树中,每个节点代表一个基因值,且树中的每个子树都缺少一个最小基因值。你的任务是找出每棵子树中缺失的最小基因值。

二、三大结论图解

为了快速理解这道难题,以下三个结论至关重要:

  1. 每个子树都有一个缺失的最小基因值: 每个子树中都存在一个缺失的最小基因值,它是该子树中所有基因值中缺失的最小值。

  2. 每个子树的缺失的最小基因值是其子树中所有基因值的最小值: 每个子树的缺失的最小基因值是其子树中所有基因值的最小值。

  3. 根节点的缺失的最小基因值为 1: 根节点没有父节点,因此其缺失的最小基因值只能是 1。

三、算法实现

基于上述结论,我们可以使用深度优先搜索(DFS)算法来解题:

  1. 从根节点开始进行 DFS。
  2. 在 DFS 过程中,记录每个子树中所有基因值的最小值。
  3. 当 DFS 到达子树的叶节点时,将该子树的缺失的最小基因值设置为其子树中所有基因值的最小值。
  4. 当 DFS 返回到子树的父节点时,将该子树的缺失的最小基因值设置为其子树中所有缺失的最小基因值的最小值。
  5. 重复以上步骤,直到 DFS 到达根节点。

四、代码示例

def find_missing_genes(tree):
    """
    :type tree: List[int]
    :rtype: List[int]
    """

    # 记录每个子树中所有基因值的最小值
    min_values = [float('inf')] * len(tree)

    # 从根节点开始进行 DFS
    dfs(tree, 0, min_values)

    # 将每个子树的缺失的最小基因值设置为其子树中所有基因值的最小值
    for i in range(len(tree)):
        if tree[i] != -1:
            min_values[i] = min(min_values[i], min_values[tree[i]])

    return min_values

def dfs(tree, node, min_values):
    """
    :type tree: List[int]
    :type node: int
    :type min_values: List[int]
    """

    # 如果当前节点是叶节点,则将当前子树的缺失的最小基因值设置为其子树中所有基因值的最小值
    if tree[node] == -1:
        min_values[node] = node + 1
        return

    # 如果当前节点不是叶节点,则继续进行 DFS
    for child in tree[node]:
        dfs(tree, child, min_values)

    # 将当前子树的缺失的最小基因值设置为其子树中所有缺失的最小基因值的最小值
    min_values[node] = min(min_values[node], min_values[tree[node]])

五、常见问题解答

  1. 为什么缺失的最小基因值一定是子树中所有基因值的最小值?
    因为如果子树中存在更小的基因值,则该基因值就不会缺失。

  2. 为什么根节点的缺失的最小基因值一定是 1?
    因为根节点没有父节点,这意味着它子树中的最小基因值只能是从 1 开始。

  3. 如何判断一个节点是否为叶节点?
    如果一个节点的子树为空,则该节点为叶节点。

  4. DFS 算法的时间复杂度是多少?
    DFS 算法的时间复杂度为 O(V + E),其中 V 为树中的节点数,E 为树中的边数。

  5. 除了 DFS 算法,还有什么其他方法可以解决这个问题?
    除了 DFS,还可以使用并查集或树状数组来解决这个问题。