查询最大基因差
难度:
标签:
题目描述
给你一棵 n
个节点的有根树,节点编号从 0
到 n - 1
。每个节点的编号表示这个节点的 独一无二的基因值 (也就是说节点 x
的基因值为 x
)。两个基因值的 基因差 是两者的 异或和 。给你整数数组 parents
,其中 parents[i]
是节点 i
的父节点。如果节点 x
是树的 根 ,那么 parents[x] == -1
。
给你查询数组 queries
,其中 queries[i] = [nodei, vali]
。对于查询 i
,请你找到 vali
和 pi
的 最大基因差 ,其中 pi
是节点 nodei
到根之间的任意节点(包含 nodei
和根节点)。更正式的,你想要最大化 vali XOR pi
。
请你返回数组 ans
,其中 ans[i]
是第 i
个查询的答案。
示例 1:

输入:parents = [-1,0,1,1], queries = [[0,2],[3,2],[2,5]] 输出:[2,3,7] 解释:查询数组处理如下: - [0,2]:最大基因差的对应节点为 0 ,基因差为 2 XOR 0 = 2 。 - [3,2]:最大基因差的对应节点为 1 ,基因差为 2 XOR 1 = 3 。 - [2,5]:最大基因差的对应节点为 2 ,基因差为 5 XOR 2 = 7 。
示例 2:

输入:parents = [3,7,-1,2,0,7,0,2], queries = [[4,6],[1,15],[0,5]] 输出:[6,14,7] 解释:查询数组处理如下: - [4,6]:最大基因差的对应节点为 0 ,基因差为 6 XOR 0 = 6 。 - [1,15]:最大基因差的对应节点为 1 ,基因差为 15 XOR 1 = 14 。 - [0,5]:最大基因差的对应节点为 2 ,基因差为 5 XOR 2 = 7 。
提示:
2 <= parents.length <= 105
- 对于每个 不是 根节点的
i
,有0 <= parents[i] <= parents.length - 1
。 parents[root] == -1
1 <= queries.length <= 3 * 104
0 <= nodei <= parents.length - 1
0 <= vali <= 2 * 105
代码结果
运行时间: 2845 ms, 内存: 107.5 MB
/*
思路:
1. 与上面的思路相同,首先构建树的结构。
2. 对于每个查询,找到对应节点到根节点路径上的所有节点。
3. 使用这些节点和查询值进行异或运算,找到最大值。
4. 返回所有查询的结果。
5. 使用 Java Stream API 进行路径节点和异或计算。
*/
import java.util.*;
import java.util.stream.*;
public class MaxGeneDifferenceStream {
public static int[] maxGeneDifference(int[] parents, int[][] queries) {
int n = parents.length;
List<Integer>[] tree = new ArrayList[n];
for (int i = 0; i < n; i++) {
tree[i] = new ArrayList<>();
}
int root = -1;
for (int i = 0; i < n; i++) {
if (parents[i] == -1) {
root = i;
} else {
tree[parents[i]].add(i);
}
}
Map<Integer, Set<Integer>> nodeToRootPath = new HashMap<>();
buildPaths(root, new HashSet<>(), tree, nodeToRootPath);
return Arrays.stream(queries)
.mapToInt(query -> getMaxXor(nodeToRootPath.get(query[0]), query[1]))
.toArray();
}
private static void buildPaths(int node, Set<Integer> path, List<Integer>[] tree, Map<Integer, Set<Integer>> nodeToRootPath) {
path.add(node);
nodeToRootPath.put(node, new HashSet<>(path));
for (int child : tree[node]) {
buildPaths(child, path, tree, nodeToRootPath);
}
path.remove(node);
}
private static int getMaxXor(Set<Integer> path, int val) {
return path.stream()
.mapToInt(p -> val ^ p)
.max()
.orElse(0);
}
public static void main(String[] args) {
int[] parents = {3, 7, -1, 2, 0, 7, 0, 2};
int[][] queries = {{4, 6}, {1, 15}, {0, 5}};
System.out.println(Arrays.toString(maxGeneDifference(parents, queries))); // 输出 [6, 14, 7]
}
}
解释
方法:
题解利用字典树(Trie)结合深度优先搜索(DFS)来解决最大基因差问题。首先,根据输入的parents数组,构建一棵树并找出根节点。对每个节点,记录所有相关的查询。然后通过DFS遍历树,同时使用字典树动态地记录当前路径上的节点值。每次访问一个节点时,将其值加入字典树中,并对所有在该节点上的查询执行查询操作,即使用字典树寻找与查询值的最大异或结果。遍历完子节点后,从字典树中删除当前节点值以防止对其他路径的影响。这样可以确保每次查询都只与从当前节点到根节点的路径相关联。
时间复杂度:
O((n + q) * logM)
空间复杂度:
O(n + q + M*2^M)
代码细节讲解
🦆
如何保证在删除字典树中的节点时,不会影响到其他分支的查询结果?
▷🦆
在字典树中查询最大异或值时,为何优先选择与当前位异或结果为1的分支?
▷🦆
字典树的结构如何确保能够有效地存储和查询各个节点的基因值?
▷🦆
DFS遍历时,字典树中节点的计数是如何帮助管理路径上的节点的?
▷