LeetCode 题解工作台

统计可能的树根数目

Alice 有一棵 n 个节点的树,节点编号为 0 到 n - 1 。树用一个长度为 n - 1 的二维整数数组 edges 表示,其中 edges[i] = [a i , b i ] ,表示树中节点 a i 和 b i 之间有一条边。 Alice 想要 Bob 找到这棵树的根。她允许 Bob 对这…

category

5

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

困难 · 数组·哈希·扫描

bolt

答案摘要

我们先遍历题目给定的边集合 ,将其转换为邻接表 ,其中 表示节点 的所有邻接节点。用哈希表 记录题目给定的猜测集合 。 接下来,我们先从节点 开始,进行一次 DFS,统计从节点 出发,能够到达的所有节点中,有多少条边在 中。我们用变量 记录这个数量。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 数组·哈希·扫描 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

Alice 有一棵 n 个节点的树,节点编号为 0n - 1 。树用一个长度为 n - 1 的二维整数数组 edges 表示,其中 edges[i] = [ai, bi] ,表示树中节点 aibi 之间有一条边。

Alice 想要 Bob 找到这棵树的根。她允许 Bob 对这棵树进行若干次 猜测 。每一次猜测,Bob 做如下事情:

  • 选择两个 不相等 的整数 u 和 v ,且树中必须存在边 [u, v] 。
  • Bob 猜测树中 u 是 v 的 父节点 。

Bob 的猜测用二维整数数组 guesses 表示,其中 guesses[j] = [uj, vj] 表示 Bob 猜 uj 是 vj 的父节点。

Alice 非常懒,她不想逐个回答 Bob 的猜测,只告诉 Bob 这些猜测里面 至少 有 k 个猜测的结果为 true 。

给你二维整数数组 edges ,Bob 的所有猜测和整数 k ,请你返回可能成为树根的 节点数目 。如果没有这样的树,则返回 0

 

示例 1:

输入:edges = [[0,1],[1,2],[1,3],[4,2]], guesses = [[1,3],[0,1],[1,0],[2,4]], k = 3
输出:3
解释:
根为节点 0 ,正确的猜测为 [1,3], [0,1], [2,4]
根为节点 1 ,正确的猜测为 [1,3], [1,0], [2,4]
根为节点 2 ,正确的猜测为 [1,3], [1,0], [2,4]
根为节点 3 ,正确的猜测为 [1,0], [2,4]
根为节点 4 ,正确的猜测为 [1,3], [1,0]
节点 0 ,1 或 2 为根时,可以得到 3 个正确的猜测。

示例 2:

输入:edges = [[0,1],[1,2],[2,3],[3,4]], guesses = [[1,0],[3,4],[2,1],[3,2]], k = 1
输出:5
解释:
根为节点 0 ,正确的猜测为 [3,4]
根为节点 1 ,正确的猜测为 [1,0], [3,4]
根为节点 2 ,正确的猜测为 [1,0], [2,1], [3,4]
根为节点 3 ,正确的猜测为 [1,0], [2,1], [3,2], [3,4]
根为节点 4 ,正确的猜测为 [1,0], [2,1], [3,2]
任何节点为根,都至少有 1 个正确的猜测。

 

提示:

  • edges.length == n - 1
  • 2 <= n <= 105
  • 1 <= guesses.length <= 105
  • 0 <= ai, bi, uj, vj <= n - 1
  • ai != bi
  • uj != vj
  • edges 表示一棵有效的树。
  • guesses[j] 是树中的一条边。
  • guesses 是唯一的。
  • 0 <= k <= guesses.length
lightbulb

解题思路

方法一:树形 DP(换根)

我们先遍历题目给定的边集合 edgesedges,将其转换为邻接表 gg,其中 g[i]g[i] 表示节点 ii 的所有邻接节点。用哈希表 gsgs 记录题目给定的猜测集合 guessesguesses

接下来,我们先从节点 00 开始,进行一次 DFS,统计从节点 00 出发,能够到达的所有节点中,有多少条边在 guessesguesses 中。我们用变量 cntcnt 记录这个数量。

然后,我们再从节点 00 开始,进行一次 DFS,统计以每个点为根的树中,有多少条边在 guessesguesses 中。如果这个数量大于等于 kk,则说明该节点是一个可能的根节点,我们将答案加 11

因此,问题就转化为了求以每个点为根的树中,有多少条边在 guessesguesses 中。我们已经知道了从节点 00 出发,能够到达的所有节点中,有多少条边在 guessesguesses 中,即 cntcnt。我们可以通过在 DFS 中,将 cntcnt 的值加上或减去当前边是否在 guessesguesses 中,来维护这个值。

假设我们当前遍历到节点 ii,此时 cntcnt 表示以 ii 为根节点,有多少条边在 guessesguesses 中。那么对于 ii 的每个邻接节点 jj,我们要计算以 jj 为根节点,有多少条边在 guessesguesses 中。如果 (i,j)(i, j)guessesguesses 中,那么以 jj 为根节点的,就不存在 (i,j)(i, j) 这条边,因此 cntcnt 的值要减去 11。如果 (j,i)(j, i)guessesguesses 中,那么以 jj 为根节点的,要多出一条 (i,j)(i, j) 这条边,因此 cntcnt 的值要加上 11。即 f[j]=f[i]+(j,i)guesses(i,j)guessesf[j] = f[i] + (j, i) \in guesses - (i, j) \in guesses。其中 f[i]f[i] 表示以 ii 为根节点,有多少条边在 guessesguesses 中。

时间复杂度 O(n+m)O(n + m),空间复杂度 O(n+m)O(n + m)。其中 nnmm 分别为 edgesedgesguessesguesses 的长度。

相似题目:

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
30
31
32
33
class Solution:
    def rootCount(
        self, edges: List[List[int]], guesses: List[List[int]], k: int
    ) -> int:
        def dfs1(i, fa):
            nonlocal cnt
            for j in g[i]:
                if j != fa:
                    cnt += gs[(i, j)]
                    dfs1(j, i)

        def dfs2(i, fa):
            nonlocal ans, cnt
            ans += cnt >= k
            for j in g[i]:
                if j != fa:
                    cnt -= gs[(i, j)]
                    cnt += gs[(j, i)]
                    dfs2(j, i)
                    cnt -= gs[(j, i)]
                    cnt += gs[(i, j)]

        g = defaultdict(list)
        for a, b in edges:
            g[a].append(b)
            g[b].append(a)
        gs = Counter((u, v) for u, v in guesses)
        cnt = 0
        dfs1(0, -1)
        ans = 0
        dfs2(0, -1)
        return ans
speed

复杂度分析

指标
时间Depends on the final approach
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Does the candidate recognize that hash table lookups can optimize the guess validation step?

  • question_mark

    Can the candidate discuss how to efficiently check multiple nodes while avoiding redundant calculations?

  • question_mark

    Is the candidate aware of the computational limits with respect to the input size, particularly in terms of time and space complexity?

warning

常见陷阱

外企场景
  • error

    Failing to efficiently count correct guesses for each root node, leading to poor performance with large input sizes.

  • error

    Overcomplicating the problem by ignoring the potential for hashing and array scanning to simplify the solution.

  • error

    Not considering the impact of tree structure on the possible root candidates and incorrectly assuming multiple valid roots without checking all conditions.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Modify the problem to check for a higher number of correct guesses, requiring adjustments to the threshold `k`.

  • arrow_right_alt

    Introduce additional constraints such as limiting the number of guesses Bob can make, altering the complexity and optimization needs.

  • arrow_right_alt

    Test with larger trees and ensure that performance scales well for up to `n = 105` and `g = 105`.

help

常见问题

外企场景

统计可能的树根数目题解:数组·哈希·扫描 | LeetCode #2581 困难