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
。
示例 1:
输入: ["TreeAncestor","getKthAncestor","getKthAncestor","getKthAncestor"] [[7,[-1,0,0,1,1,2,2]],[3,1],[5,2],[6,3]] 输出: [null,1,0,-1] 解释: TreeAncestor treeAncestor = new TreeAncestor(7, [-1, 0, 0, 1, 1, 2, 2]); treeAncestor.getKthAncestor(3, 1); // 返回 1 ,它是 3 的父节点 treeAncestor.getKthAncestor(5, 2); // 返回 0 ,它是 5 的祖父节点 treeAncestor.getKthAncestor(6, 3); // 返回 -1 因为不存在满足要求的祖先节点
提示:
-
1 <= k <= n <= 5 * 1e4
-
parent[0] == -1
表示编号为0
的节点是根节点。 - 对于所有的
0 < i < n
,0 <= parent[i] < n
总成立 -
0 <= node < n
- 至多查询
5 * 1e4
次
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/kth-ancestor-of-a-tree-node
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
做题结果
成功,根据经验想了折半法,倍增是从题解区学到的
方法1:折半
1. 大概50000的范围,n方取1e8,存不下
2. 不存直接找,最坏 n*5e4,时间超
3. 那可以平均一下,2个0分给内存,2个0分给查找,那么,存前100个k就行了,内存和查找耗时就都变为1e6,一定可以通过
class TreeAncestor {
int n;
int[] parent;
int[] colors;
int[][] parentK;
public TreeAncestor(int n, int[] parent) {
this.n = n;
this.parent = parent;
parentK = new int[n][101];
for(int i = 0; i < n; i++){
Arrays.fill(parentK[i],-1);
}
for(int i = 0; i < n; i++){
for(int curr = i,j = 0; j <= 100&&curr!=-1; j++){
parentK[i][j]=curr;
curr = parent[curr];
}
}
}
public int getKthAncestor(int node, int k) {
if(node == -1) return -1;
if(k>100) return getKthAncestor(parentK[node][100],k-100);
return parentK[node][k];
}
}
方法2:倍增(新学)
参考:力扣在逐渐把 ACM 模板题搬上来,这个问题是 Binary Lifting
假设k=3,那么k=2e0+2e1,也就是可以通过两个二进制求和得到,那么对于任意一个 int 类型的k,都可以将它分为2进制次数相加。也就是平均分到 17个格子里,分别代表一个二进制数位即可实现在logn时间内找到所有的k
1. 默认-1,0层是自己,1层是parent[i]
2. 对于dp[i][j]=dp[dp[i][j-1]][j],也就是走4步等于走2步再走2步,j代表走 (1<<j)位的父节点找到的元素。特别地,如果走到-1,则再往上也是-1.这种情况处理为 dp[0][j-1],0节点是根节点,它的任意非0层父节点必然为-1
3. 查找,分解二进制的每一位向前搜索,比如10=2e3+2e2
class TreeAncestor {
int n;
int[] colors;
int[][] parentK;
public TreeAncestor(int n, int[] parent) {
this.n = n;
parentK = new int[n][18];
for(int i = 0; i < n;i++){
Arrays.fill(parentK[i],-1);
}
for(int i = 0; i < n; i++){
parentK[i][0] = i;
parentK[i][1] = parent[i];
}
for(int j = 2; j < 17; j++){
for(int i = 0; i < n; i++){
parentK[i][j] = parentK[Math.max(parentK[i][j-1],0)][j-1];
}
}
}
public int getKthAncestor(int node, int k) {
for(int i = 0; i < 18&&node!=-1; i++){
if(((1<<i)&k)>0){
node = parentK[node][i+1];
}
}
return node;
}
}