[1483. 树节点的第 K 个祖先]
给你一棵树,树上有 n 个节点,按从 0 到 n-1 编号。树以父节点数组的形式给出,其中 parent[i] 是节点 i 的父节点。树的根节点是编号为 0 的节点。
树节点的第 k 个祖先节点是从该节点到根节点路径上的第 k 个节点。
实现 TreeAncestor 类:
TreeAncestor(int n, int[] parent)对树和父数组中的节点数初始化对象。getKthAncestor``(int node, int k)返回节点node的第k个祖先节点。如果不存在这样的祖先节点,返回-1。
思路如下
这个问题可以通过预处理父节点数组来解决,以便在查询时能够快速找到第k个祖先节点。我们可以使用一个二维数组dp,其中dp[i][j]表示节点i的第2^j个祖先。这样,我们可以在O(logk)的时间内找到节点的第k个祖先。 首先,我们需要初始化dp数组。对于每个节点i,它的第1个祖先(即2^0)就是parent[i]。然后,我们可以使用动态规划的方法来填充dp数组的其余部分。对于每个节点i和每个j>0,节点i的第2^j个祖先dp[i][j]就是它的第2^(j-1)个祖先的第2^(j-1)个祖先,即dp[dp[i][j-1]][j-1]。 然后,当我们需要查询节点node的第k个祖先时,我们可以将k表示为二进制形式,然后从高位到低位依次找到每个为1的位对应的祖先。
代码实现:
class TreeAncestor {
int[][] dp;
public TreeAncestor(int n, int[] parent) {
int m = (int)(Math.log(n) / Math.log(2)) + 1;
dp = new int[n][m];
for (int i = 0; i < n; i++) {
dp[i][0] = parent[i];
}
for (int j = 1; j < m; j++) {
for (int i = 0; i < n; i++) {
if (dp[i][j - 1] != -1) {
dp[i][j] = dp[dp[i][j - 1]][j - 1];
} else {
dp[i][j] = -1;
}
}
}
}
public int getKthAncestor(int node, int k) {
int m = dp[0].length;
for (int j = m - 1; j >= 0; j--) {
if ((k & (1 << j)) != 0) {
node = dp[node][j];
if (node == -1) {
return -1;
}
}
}
return node;
}