0
点赞
收藏
分享

微信扫一扫

1483. 树节点的第 K 个祖先 折半/倍增


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:

1483. 树节点的第 K 个祖先 折半/倍增_sql

输入: ["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;
}
}

举报

相关推荐

0 条评论