力扣 1483. 树节点的第 K 个祖先

力扣 1483. 树节点的第 K 个祖先

题目地址:https://leetcode.cn/problems/kth-ancestor-of-a-tree-node/

  1. 暴力查找(超时)
  2. 哈希查找(超空间)
  3. 树上倍增

预处理

ancestor 数组记录了第 i 个 node 的倍增祖先,假设 i 为 100,即
ancestor[100][0] 记录了第 100 个 node 的第 1 个祖先
ancestor[100][1] 记录了第 100 个 node 的第 2 个祖先
ancestor[100][2] 记录了第 100 个 node 的第 4 个祖先
……
ancestor[100][j] 记录了第 100 个 node 的第 2j 个祖先

动态规划转移方程

ancestor[i][j] = ancestor[k][j-1], k = ancestor[i][j-1]
即当前节点的第 2j个祖先,是他的第 2j-1 个祖先的第 2j-1 个祖先

查询

查询第 100 个 node 的第 k 个祖先节点,假设 k 为 25,即
k 的二进制表示为 11001,原查询可拆分为:
查询第 100 个 node
的第 20 个祖先节点
的第 23 个祖先节点
的第 24 个祖先节点
如下图:

参考代码(TS)

/**
 * 3. 倍增
 * 时间 O(nlogn + logk)  476ms   33%
 * 空间 O(nlogn)         85.8mb  72%
 */
class TreeAncestor {
    private level: number;
    private ancestor: number[][];

    /**
     * 转移方程 ancestor[i][j] = ancestor[k][j-1], k = ancestor[i][j-1]
     * i 的倍增层有没有父,有就跳到父的倍增层
     * 当前节点的第 2^j 个祖先,是他的第 2^(j-1) 个祖先的第 2^(j-1) 个祖先
     * 时间 O(nlogn)
     * 空间 O(nlogn)
     */
    constructor(n: number, parent: number[]) {
        this.level = Math.ceil(Math.log2(n)); // log2(50000) = 16

        this.ancestor = parent.map((pi) => {
            const arr = new Array(this.level);
            arr.fill(-1);
            arr[0] = pi;
            return arr;
        });

        for (let j = 1; j < this.level; j++) {
            for (let i = 0; i < n; i++) {
                const k = this.ancestor[i][j - 1];
                if (k > -1) {
                    this.ancestor[i][j] = this.ancestor[k][j - 1];
                }
            }
        }
    }

    /**
     * 返回树节点的第 K 个祖先节点
     * 时间 O(logk)
     * 空间 O(1)
     */
    getKthAncestor(node: number, k: number): number {
        let _node = node;
        for (let j = 0; j < this.level; j++) {
            if (((k >> j) & 1) !== 0) {
                _node = this.ancestor[_node][j];
                if (_node === -1) return -1;
            }
        }
        return _node === node ? -1 : _node;
    }
}

其他相关:
BL(Binary Lifting)倍增法
ST(Sparse Table)稀疏表
LCA(Least Common Ancestors)最近公共祖先问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值