【每日一题Day235】LC1483树节点的第 K 个祖先 | 倍增

news/2024/11/14 11:52:58/

树节点的第 K 个祖先【LC1483】

给你一棵树,树上有 n 个节点,按从 0n-1 编号。树以父节点数组的形式给出,其中 parent[i] 是节点 i 的父节点。树的根节点是编号为 0 的节点。

树节点的第 k 个祖先节点是从该节点到根节点路径上的第 k 个节点。

实现 TreeAncestor 类:

  • TreeAncestor(int n, int[] parent) 对树和父数组中的节点数初始化对象。
  • getKthAncestor``(int node, int k) 返回节点 node 的第 k 个祖先节点。如果不存在这样的祖先节点,返回 -1

新知识++

  • 思路

    • 暴力:从每个node出发,往上跳 k k k次,时间复杂度为 O ( m k ) \mathcal{O}(mk) O(mk),会超时

    • 优化:每次跳跃时不止跳一个节点->使用倍增算法,预处理每个节点的 2 i 2^i 2i个祖先节点,某个节点的第 2 i + 1 2^{i+1} 2i+1个祖先节点为其第 2 i 2^i 2i个祖先节点的第 2 i 2^i 2i个祖先节点,如果其 2 i 2^i 2i个祖先节点不存在,那么后续的祖先节点也不存在。递推公式如下
      d p [ x ] [ i + 1 ] = d p [ d p [ x ] [ i ] ] [ i ] dp[x][i+1] = dp[dp[x][i]][i] dp[x][i+1]=dp[dp[x][i]][i]

    • 每次查询的 k k k可以由若干2的幂组成,因此可以快速到达第 k k k个祖先节点。

  • 实现

    class TreeAncestor {private int[] depth;private int[][] pa;public TreeAncestor(int[][] edges) {int n = edges.length + 1;int m = 32 - Integer.numberOfLeadingZeros(n); // n 的二进制长度List<Integer> g[] = new ArrayList[n];Arrays.setAll(g, e -> new ArrayList<>());for (var e : edges) { // 节点编号从 0 开始int x = e[0], y = e[1];g[x].add(y);g[y].add(x);}depth = new int[n];pa = new int[n][m];dfs(g, 0, -1);for (int i = 0; i < m - 1; i++) {for (int x = 0; x < n; x++) {int p = pa[x][i];pa[x][i + 1] = p < 0 ? -1 : pa[p][i];}}}private void dfs(List<Integer>[] g, int x, int fa) {pa[x][0] = fa;for (int y : g[x]) {if (y != fa) {depth[y] = depth[x] + 1;dfs(g, y, x);}}}public int getKthAncestor(int node, int k) {for (; k > 0; k &= k - 1)node = pa[node][Integer.numberOfTrailingZeros(k)];return node;}public int getLCA(int x, int y) {if (depth[x] > depth[y]) {int tmp = y;y = x;x = tmp;}// 使 y 和 x 在同一深度y = getKthAncestor(y, depth[y] - depth[x]);if (y == x)return x;for (int i = pa[x].length - 1; i >= 0; i--) {int px = pa[x][i], py = pa[y][i];if (px != py) {x = px;y = py;}}return pa[x][0];}
    }作者:灵茶山艾府
    链接:https://leetcode.cn/problems/kth-ancestor-of-a-tree-node/solutions/2305895/mo-ban-jiang-jie-shu-shang-bei-zeng-suan-v3rw/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    • 复杂度
      • 时间复杂度:预处理 O ( n log ⁡ n ) \mathcal{O}(n\log n) O(nlogn),每个询问 O ( log ⁡ n ) \mathcal{O}(\log n) O(logn)
      • 空间复杂度:预处理 O ( n log ⁡ n ) \mathcal{O}(n\log n) O(nlogn)

http://www.ppmy.cn/news/343578.html

相关文章

如何在7段和16段LED显示屏中表示数字和字母?

三种 7 段显示代表英文数字的例子和 14 段显示代表英文的例子。 7段显示器和1段显示器在日常生活中很常见&#xff0c;它们都以阿拉伯数字和英文字母表示信息&#xff0c;除了16段显示器可以显示完整的阿拉伯数字、大写字母和小写英文字母; 最常用的7段显示阿拉伯数字也可以代表…

led屏幕条形液晶

条形液晶屏的应用和选型    条形液晶屏是新时代的新产物&#xff0c;顾名思义&#xff0c;条形液晶屏也就是一个长宽比大于2:1的液晶屏&#xff0c;在我们学习生活中的每个不同角落发展都有广泛应用&#xff0c;比如:商场进行广告、公交站台、地铁可以显示、广告设计标牌、车…

3 个技巧,让你像技术专家一样解决编码问题

「我应该如何提高解决问题的能力&#xff1f;尽管我掌握了 JavaScript&#xff0c;却无法解决实际问题或理解复杂的 JavaScript 代码。」 经常有年轻的开发者朋友问我类似的问题。对开发者来说&#xff0c;解决问题非常重要。编写优秀的代码是一门创造性的艺术&#xff0c;而要…

探索LowLatency的HLS低延迟直播协议

HLS全称为HTTP Live Streaming&#xff0c;其中m3u8作为描述协议&#xff0c;指向一系列切片文件。支持多码流与自适应码率&#xff0c;支持广告无缝播放&#xff0c;支持CMAF协议的低延时直播&#xff0c;也支持CDN动态选择。 我们先看下HLS整体架构&#xff0c;由三部分构成…

如何快速完成TensorRT模型生成和加速

0. 简介 之前作者在《深度学习之从Python到C》介绍了一些比较传统的方法&#xff0c;主要侧重介绍了如何将pth和pytorch传统形式文件转化为onnx的文件&#xff0c;这个部分的内容&#xff0c;也可以主要看一下《PyTorch模型部署&#xff1a;pth转onnx跨框架部署详解代码》这个…

Java之旅(十五)

Java 抽象类 Java抽象类&#xff08;Abstract Class&#xff09;是一种特殊的Java类&#xff0c;用于定义一个模板结构和方法集合&#xff0c;为子类提供一个共同的基础。抽象类不能直接实例化&#xff0c;只能用于被继承。抽象类可以包含抽象方法&#xff08;abstract method…

如何制作电子印章?电脑做印章最简单的方法是什么?

现在随着时代发展&#xff0c;电子印章已经越来越常见了&#xff0c;尤其是在很多贴吧、论坛里面都可以设置签名档&#xff0c;有很多人就把自己的个人印章做成了签名档&#xff0c;非常美观又有趣&#xff0c;那么我们如果也想制作属于自己的电子印章应该怎么办呢&#xff1f;…

透光按键激光打标机,激光打标机

按键”在我们的生活中随处可见&#xff0c;用途广泛。这些键每天都是用手指摩擦的&#xff0c;比如&#xff1a;灯键、电脑键盘键、汽车内饰键等等。因为这些按键上的信息给我们的生活带来了便利&#xff0c;在长期的接触中很容易慢慢模糊甚至脱落。透明按键激光打标机是电子行…