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

news/2024/7/2 23:30:51

力扣 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)最近公共祖先问题


http://lihuaxi.xjx100.cn/news/1241533.html

相关文章

Linux系统实现虚拟内存教程

Linux系统实现虚拟内存有两种方法&#xff1a;交换分区&#xff08;swap分区&#xff09;和交换文件&#xff0c; 一、交换文件 查看内存&#xff1a;free -m , -m是显示单位为MB&#xff0c;-g单位GB free -g 创建一个文件&#xff1a;touch命令用于修改…

Redis6之数据类型

常见数据类型 String字符串 简介 String是最基本的数据类型&#xff0c;是二进制安全的&#xff0c;一个key对应一个value 常用命令 1.set <key> <value> :添加键值对 2.get <key>&#xff1a;查询对应键值对 3.append <key> <value>&#xf…

微信小程序开发大坑盘点

微信小程序开发大坑盘点 起因 前几天心血来潮&#xff0c;想给学校设计个一站式校园小程序&#xff0c;可以查询成绩&#xff0c;考试信息&#xff0c;课表之类的&#xff08;本来想法里是还想包括一些社交功能的&#xff0c;但这个因为资质问题暂且搁置了&#xff09;。其实…

pandas---数据合并(concat、append、merge)

1. concat函数 pd.concat([data1, data2], axis1) 按照行或列进行合并&#xff0c;axis0为列索引&#xff0c;axis1为行索引。 df1 make_df([1, 2], [A, B]) df2 make_df([3, 4], [A, B]) display(df1, df2) # 默认上下合并&#xff0c;垂直合并 pd.concat([df1, df2]) …

RabbitMq消息堆积问题及惰性队列

消息堆积问题 当生产者发送消息的速度超过了消费者处理的速度&#xff0c;就会导致队列的消息堆积&#xff0c;知道队列存储消息达到上限。最早接受的消息&#xff0c;可能就会成为死信&#xff0c;会被丢弃&#xff0c;这就是消息堆积问题。 解决消费对接问题 1.增加更多的消…

希尔贝壳邀您参加2023深圳国际人工智能展览会

2023深圳国际人工智能展览会“AIE”将于2023年5月16-18日在深圳国际会展中心 (宝安)举办&#xff0c;希尔贝壳受邀参加&#xff0c;展位号&#xff1a;A331。 伴随着智能行业的快速发展&#xff0c;展会已被越来越多的企业列入每年必选展会&#xff0c;也成为各采购商选购的理…

Android-MTK平台功能需求解决:客户电池NTC功能(高低温报警功能)--第2天分析与解决

一、进一步修改代码内容-过程 今日了解到&#xff0c;昨日所修改的kernel层的mtk_charger.h文件位于A13部分&#xff0c;然6769平台A13部分的kernel层不参与编译&#xff0c;那么修改后再编译等等后续操作验证结果自然无效&#xff0c;参与编译kernel层是A12部分的kernel-4.19…

springcloud 父项目建立(一)

我们开发项目&#xff0c;现在基本都用到maven&#xff0c;以及用父子项目&#xff0c;以及公共模块依赖&#xff0c;来构建方便扩展的项目体系&#xff1b; 首先我们建立父项目 microservice &#xff0c;主要是一个pom&#xff0c;管理module&#xff0c;以及管理依赖&#x…