重构一棵树的方案数
难度:
标签:
题目描述
给你一个数组 pairs
,其中 pairs[i] = [xi, yi]
,并且满足:
pairs
中没有重复元素xi < yi
令 ways
为满足下面条件的有根树的方案数:
- 树所包含的所有节点值都在
pairs
中。 - 一个数对
[xi, yi]
出现在pairs
中 当且仅当xi
是yi
的祖先或者yi
是xi
的祖先。 - 注意:构造出来的树不一定是二叉树。
两棵树被视为不同的方案当存在至少一个节点在两棵树中有不同的父节点。
请你返回:
- 如果
ways == 0
,返回0
。 - 如果
ways == 1
,返回1
。 - 如果
ways > 1
,返回2
。
一棵 有根树 指的是只有一个根节点的树,所有边都是从根往外的方向。
我们称从根到一个节点路径上的任意一个节点(除去节点本身)都是该节点的 祖先 。根节点没有祖先。
示例 1:

输入:pairs = [[1,2],[2,3]] 输出:1 解释:如上图所示,有且只有一个符合规定的有根树。
示例 2:

输入:pairs = [[1,2],[2,3],[1,3]] 输出:2 解释:有多个符合规定的有根树,其中三个如上图所示。
示例 3:
输入:pairs = [[1,2],[2,3],[2,4],[1,5]] 输出:0 解释:没有符合规定的有根树。
提示:
1 <= pairs.length <= 105
1 <= xi < yi <= 500
pairs
中的元素互不相同。
代码结果
运行时间: 177 ms, 内存: 44.2 MB
/*
题目思路:
1. 利用 Java Stream API 对 pairs 进行处理。
2. 构建图和节点入度的关系。
3. 确定根节点,并检查图的连通性和有效性。
*/
import java.util.*;
import java.util.stream.Collectors;
public class SolutionStream {
public int checkWays(int[][] pairs) {
Map<Integer, Set<Integer>> graph = Arrays.stream(pairs)
.flatMapToInt(Arrays::stream)
.boxed()
.distinct()
.collect(Collectors.toMap(k -> k, v -> new HashSet<>()));
Map<Integer, Long> indegree = Arrays.stream(pairs)
.flatMapToInt(Arrays::stream)
.boxed()
.collect(Collectors.groupingBy(e -> e, Collectors.counting()));
Arrays.stream(pairs).forEach(pair -> {
graph.get(pair[0]).add(pair[1]);
graph.get(pair[1]).add(pair[0]);
});
int root = graph.keySet().stream()
.filter(node -> indegree.get(node) == graph.size() - 1)
.findFirst()
.orElse(-1);
if (root == -1) return 0;
return dfs(graph, new HashSet<>(), root) ? 1 : 2;
}
private boolean dfs(Map<Integer, Set<Integer>> graph, Set<Integer> visited, int node) {
visited.add(node);
return graph.get(node).stream()
.allMatch(neighbor -> visited.contains(neighbor) || dfs(graph, visited, neighbor)) && visited.size() == graph.size();
}
}
解释
方法:
该题解采用了图论的方法来解决问题。首先,将pairs中的每个数对看作无向图的边,构建邻接表adj,记录每个节点与之直接连接的节点。通过邻接表,可以判断任两个节点之间的直接关系。然后,将节点按照它们的连接数(度)从高到低排序。这一步是为了后续确定树的根节点,因为根节点在无向图中的连接数最多。接着,遍历每个节点,尝试将其作为子节点,寻找可能的父节点。父节点的条件是:必须与子节点直接相连,且父节点的度要高于子节点的度。如果找到符合条件的父节点,还需进一步检查,确保子节点的邻接节点都包含在父节点的邻接节点集中。如果在任何节点上发现不满足条件的情况,则返回0。如果存在多个节点可以有相同数量的连接,可能存在多种不同的树结构,设置标志multiAns为True。最后,根据是否存在多个解来返回1或2。
时间复杂度:
O(n^2)
空间复杂度:
O(n + m)
代码细节讲解
🦆
在构建无向图时,`pairs[i] = [xi, yi]`且`xi < yi`,为什么邻接表会将每个数对视为无向边而不是有向边,这与题目中的祖先关系定义是否矛盾?
▷🦆
排序节点时,为什么选择以节点的连接数(度)从高到低进行排序,这一步骤是如何帮助确定树的根节点的?
▷🦆
题解中提到,如果根节点的连接数不等于总节点数减一,则返回0。请问这种情况下为什么一定不存在有效的树结构?
▷🦆
在寻找每个子节点的可能父节点时,为什么必须要求父节点的连接数要高于子节点的连接数?这一条件在树结构中意味着什么?
▷