LeetCode 题解工作台

移除子树后的二叉树高度

给你一棵 二叉树 的根节点 root ,树中有 n 个节点。每个节点都可以被分配一个从 1 到 n 且互不相同的值。另给你一个长度为 m 的数组 queries 。 你必须在树上执行 m 个 独立 的查询,其中第 i 个查询你需要执行以下操作: 从树中 移除 以 queries[i] 的值作为根节点…

category

5

题型

code_blocks

4

代码语言

hub

3

相关题

当前训练重点

困难 · 二分·树·traversal

bolt

答案摘要

我们先通过一次 DFS 遍历的深度,存放在哈希表 中,其中 表示节点 的深度。 然后我们设计一个函数 $dfs(root, depth, rest)$,其中:

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 二分·树·traversal 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一棵 二叉树 的根节点 root ,树中有 n 个节点。每个节点都可以被分配一个从 1n 且互不相同的值。另给你一个长度为 m 的数组 queries

你必须在树上执行 m独立 的查询,其中第 i 个查询你需要执行以下操作:

  • 从树中 移除queries[i] 的值作为根节点的子树。题目所用测试用例保证 queries[i] 等于根节点的值。

返回一个长度为 m 的数组 answer ,其中 answer[i] 是执行第 i 个查询后树的高度。

注意:

  • 查询之间是独立的,所以在每个查询执行后,树会回到其 初始 状态。
  • 树的高度是从根到树中某个节点的 最长简单路径中的边数

 

示例 1:

输入:root = [1,3,4,2,null,6,5,null,null,null,null,null,7], queries = [4]
输出:[2]
解释:上图展示了从树中移除以 4 为根节点的子树。
树的高度是 2(路径为 1 -> 3 -> 2)。

示例 2:

输入:root = [5,8,9,2,1,3,7,4,6], queries = [3,2,4,8]
输出:[3,2,3,2]
解释:执行下述查询:
- 移除以 3 为根节点的子树。树的高度变为 3(路径为 5 -> 8 -> 2 -> 4)。
- 移除以 2 为根节点的子树。树的高度变为 2(路径为 5 -> 8 -> 1)。
- 移除以 4 为根节点的子树。树的高度变为 3(路径为 5 -> 8 -> 2 -> 6)。
- 移除以 8 为根节点的子树。树的高度变为 2(路径为 5 -> 9 -> 3)。

 

提示:

  • 树中节点的数目是 n
  • 2 <= n <= 105
  • 1 <= Node.val <= n
  • 树中的所有值 互不相同
  • m == queries.length
  • 1 <= m <= min(n, 104)
  • 1 <= queries[i] <= n
  • queries[i] != root.val
lightbulb

解题思路

方法一:两次 DFS

我们先通过一次 DFS 遍历的深度,存放在哈希表 dd 中,其中 d[x]d[x] 表示节点 xx 的深度。

然后我们设计一个函数 dfs(root,depth,rest)dfs(root, depth, rest),其中:

  • root 表示当前节点;
  • depth 表示当前节点的深度;
  • rest 表示删除当前节点后,树的高度。

函数的计算逻辑如下:

如果节点为空,直接返回。否则,我们将 depth11,然后将 rest 保存在 res 中。

接着递归遍历左右子树。

递归左子树前,我们计算从根节点到当前节点右子树最深节点的就,即 depth+d[root.right]depth+d[root.right],然后将其与 rest 比较,取较大值作为左子树的 rest

递归右子树前,我们计算从根节点到当前节点左子树最深节点的就,即 depth+d[root.left]depth+d[root.left],然后将其与 rest 比较,取较大值作为右子树的 rest

最后返回每个查询节点对应的结果值即可。

时间复杂度 O(n+m)O(n+m),空间复杂度 O(n)O(n)。其中 nnmm 分别是树的节点数和查询数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def treeQueries(self, root: Optional[TreeNode], queries: List[int]) -> List[int]:
        def f(root):
            if root is None:
                return 0
            l, r = f(root.left), f(root.right)
            d[root] = 1 + max(l, r)
            return d[root]

        def dfs(root, depth, rest):
            if root is None:
                return
            depth += 1
            res[root.val] = rest
            dfs(root.left, depth, max(rest, depth + d[root.right]))
            dfs(root.right, depth, max(rest, depth + d[root.left]))

        d = defaultdict(int)
        f(root)
        res = [0] * (len(d) + 1)
        dfs(root, -1, 0)
        return [res[v] for v in queries]
speed

复杂度分析

指标
时间O(n + q)
空间O(n)
psychology

面试官常问的追问

外企场景
  • question_mark

    Candidate considers preprocessing depths and heights to avoid repeated computation per query.

  • question_mark

    Candidate identifies that tracking two maximum heights per level allows O(1) query resolution.

  • question_mark

    Candidate correctly handles edge cases such as removing nodes at maximum depth affecting tree height.

warning

常见陷阱

外企场景
  • error

    Recomputing tree height from scratch for each query, causing TLE for large n.

  • error

    Failing to account for the second largest height at a depth, returning wrong height when the largest node is removed.

  • error

    Incorrectly assuming subtree removal affects parent levels without adjusting maximums properly.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Compute remaining subtree sizes instead of heights after removal queries.

  • arrow_right_alt

    Answer subtree sum queries after removals using a similar traversal and precomputation.

  • arrow_right_alt

    Handle dynamic insertion and deletion with height updates using segment tree analogs.

help

常见问题

外企场景

移除子树后的二叉树高度题解:二分·树·traversal | LeetCode #2458 困难