首页 > 其他分享 >1483. 树节点的第 K 个祖先 又学了一招

1483. 树节点的第 K 个祖先 又学了一招

时间:2023-06-13 10:03:58浏览次数:41  
标签:node parent int cache 1483 祖先 又学 节点

1483. 树节点的第 K 个祖先

最开始自己的思路竟然是想构建多叉树,这样实在太蠢了,还是直接学习优秀的官解吧。

学习历程

暴力解法学习

  1. 举例说明:n = 7 parent = [-1, 0, 0, 1, 1, 2, 2]
  2. 一共七个节点 节点的值分别是:0,1,2,3,4,5,6
  1. -1:表示根节点
  2. ex:寻找节点6的祖先节点
  1. 第一个祖先节点:parent[6] = 2
  2. 第二个祖先节点:parent[2] = 0
  3. 第三个祖先节点:parent[0] = -1 -1 不存在,所以不存在第三个祖先节点
  1. 此解法时间复杂度O(k),果不其然超时了
class TreeAncestor {

    private int[] parent;


    public TreeAncestor(int n, int[] parent) {
        this.parent = parent;
    }
    
    public int getKthAncestor(int node, int k) {
        int cnt = 0;
        if(cnt == k) {
            return cnt;
        }
        while (node != -1) {
            node = parent[node];
            cnt++;
            if(cnt == k) {
                return node;
            }
        }
        return -1;
    }
}

优化暴力算法

  1. 预处理节点?需要预处理出哪些节点?----算了,想不起来,直接往下看
  2. 预处理出每一个节点的第个祖先节点,即第 2、4、6、8......个祖先节点
  1. ex:一个节点 node 的第一个祖先节点是 parent[node]
  2. ???还是看不懂,继续往下
  1. 任意 k 可以分解为若干不同的 2 的幂,ex:13 = 8 + 4 + 1
  2. 所以只需要预处理出这些 祖先节点,就可以快速地到达任意k 个祖先节点。
  1. 看到这里明白了一些,但是如何处理?继续往下看
  1. ex:
  1. 所以,可以先往上跳 8步、4步 最后 1 步。也可以 4->8->1 或者 1->8->4
  2. 无论如何只需要三次就能找到目标第13个祖先节点

如何实现该算法

  1. 在构造函数TreeAncestor中,预处理出每一个节点x的第个祖先节点,记作
  1. 若第1483. 树节点的第 K 个祖先   又学了一招_binary个祖先节点不存在,则1483. 树节点的第 K 个祖先   又学了一招_算法_02
  1. 计算方式如下
  1. 先枚举i,再枚举x。ex:cache[x][0]表示节点x的第个祖先节点,所以有
  1. cache[x][0] = parent[x]
  2. cache[x][1]:表示节点x的第个祖先节点->cache[x][1] = cache[cache[x][0]][0]
  1. 解释:求节点x的第 2 个祖先节点
  2. 其第一个祖先节点是parent[x],相当于求parent[x]的祖先节点,即parent[parent[x]]
  3. 等同于求cache[parent[parent[x]]][0]
  4. 又因为parent[x] = cache[x][0]
  5. 所以有cache[x][1] = cache[cache[x][0][0]
  1. 我丢--真的太妙了
  1. 那么可以推导出cache[x][i+1] = cache[cache[x][i]][i]
  1. 如果cache[x][i] = -1cache[x][i+1] = -1
  1. 对于i+1而言最多为
  1. ex:当1483. 树节点的第 K 个祖先   又学了一招_算法_03,1483. 树节点的第 K 个祖先   又学了一招_binary_04
  2. 意味着最多需要预处理1483. 树节点的第 K 个祖先   又学了一招_binary_05个祖先节点
  1. 构造函数预处理
  1. 首先要考虑对于参数 n,最多需要预处理多少个节点
  2. 即如何求i 1483. 树节点的第 K 个祖先   又学了一招_算法_06
private int[][] cache;

public TreeAncestor(int n, int[] parent) {
    //  numberOfLeadingZeros 计算 数字 n 对应的二进制数的长度
    int m = 32 - Integer.numberOfLeadingZeros(n);
    // 这里对于数字 1->n 分别预处理其 2^(0->m) 个节点的数据
    cache = new int[n][m];
    for(int i = 0;i < n;i++) {
        cache[i][0] = parent[i];
    }
    for(int i = 0;i < m - 1;i++) {
        for(int x = 0;x < n;x++) {
            int p = cache[x][i];
            cache[x][i + 1] = p < 0?-1:cache[p][i];
        }
    }
}
  1. 寻找第 k 个祖先节点
  1. getKthAncestor
public int getKthAncestor(int node, int k) {
    int m = 32 - Integer.numberOfLeadingZeros(k);
    for(int i = 0;i < m;i++) {
        if(((k >> i) & 1) == 1) {
            node = cache[node][i];
            if(node < 0) {
                break;
            }
        }
    }
    return node;
}

b. 另一种写法

public int getKthAncestor(int node, int k) {
    //  这里不断去去掉 k 最低位的 1
    //  相当于  1  4  8 这样跳
    for(;k > 0 && node != -1;k &= k - 1) {
        node = cache[node][Integer.numberOfTrailingOfZeros(k)];
    }
    return node;
}
  • 真是太妙了

参考

https://leetcode.cn/problems/kth-ancestor-of-a-tree-node/solution/mo-ban-jiang-jie-shu-shang-bei-zeng-suan-v3rw/

完结撒花,又学了一招

标签:node,parent,int,cache,1483,祖先,又学,节点
From: https://blog.51cto.com/u_16079703/6467241

相关文章

  • Camunda 自定义模型图后 流程节点叠在一起怎么查看
    简单写一下 后面详细补充   根据这个sql语句可以把乱码的数据转码过来SELECTcast(BYTES_ASCHAR)ASBYTES_FROM`act_ge_bytearray`WHEREID_='e4e532d0-c146-11ec-b630-18f22c5016b2'; 把转码后的xml放到CamundaModeler客户端编辑器里面去  ......
  • LC1171. 从链表中删去总和值为零的连续节点
    题目来源于力扣题库,题目链接:LC1171.从链表中删去总和值为零的连续节点Q:给你一个链表的头节点 head,请你编写代码,反复删去链表中由总和 值为0的连续节点组成的序列,直到不存在这样的序列为止。删除完毕后,请你返回最终结果链表的头节点。 你可以返回任何满足题目要求的答案。......
  • Redis集群-哨兵模式搭建(1主2从3哨兵节点)
    Redis集群-哨兵模式搭建(1主2从3哨兵节点)原创 北极星 运维记事 2023-04-2022:47 发表于四川收录于合集#redis8个主机规划类型IP地址端口号主192.168.77.1456379从1192.168.77.1466379从2192.168.77.1476379哨兵1192.168.77.14526379哨兵2......
  • 2023.6.12 树节点的第k个祖先
    可以借鉴一下求LCA问题中的倍增思想。用fa[i][j]表示i号节点的第\(2^j\)个祖先。我们只需要用动态规划预处理出这个fa数组即可。求第k个祖先,可以将k用二进制拼凑的方法划分成若干个2的整数次幂,然后利用fa数组对应地进行若干次跳跃即可,单个询问的时间复杂度\(O(logn)\)。这里由......
  • leetcode 1171. 从链表中删去总和值为零的连续节点
    给你一个链表的头节点 head,请你编写代码,反复删去链表中由总和 值为0的连续节点组成的序列,直到不存在这样的序列为止。删除完毕后,请你返回最终结果链表的头节点。你可以返回任何满足题目要求的答案。(注意,下面示例中的所有序列,都是对 ListNode 对象序列化的表示。)示例1:输入:he......
  • Leetcode 1171. 从链表中删去总和值为零的连续节点
    题目:给你一个链表的头节点 head,请你编写代码,反复删去链表中由总和 值为0的连续节点组成的序列,直到不存在这样的序列为止。删除完毕后,请你返回最终结果链表的头节点。你可以返回任何满足题目要求的答案。(注意,下面示例中的所有序列,都是对 ListNode 对象序列化的表示。)难......
  • 第四天打卡|24. 两两交换链表中的节点 ● 19.删除链表的倒数第N个节点 面试题 02.07.
    24.两两交换链表中的节点:简单的交换 19.删除链表的倒数第N个节点: ●  面试题 02.07. 链表相交:这题没看过答案真的写不出来。太巧妙了  142.环形链表II:这题写过但是忘记怎么解的了还是看的答案。下次不能忘记  ......
  • 2023.6.11 从链表中删去总和值为0的节点
    对一个序列进行前缀和处理,假设p处前缀和与q处前缀和相等,说明\((p,q)\)之间的序列和为0。因此我们可以遍历一次链表,预处理出前缀和,同时用哈希表记录,哈希表的key为前缀和,value为所处节点。遇到相同的key时,直接覆盖,这样哈希表存储的就是前缀和为key的最后一个节点。第二次遍历......
  • 2023-06-10:给定一个由 n 个节点组成的网络,用 n x n 个邻接矩阵 graph 表示 在节点网络
    2023-06-10:给定一个由n个节点组成的网络,用nxn个邻接矩阵graph表示在节点网络中,只有当graph[i][j]=1时,节点i能够直接连接到另一个节点j。一些节点initial最初被恶意软件感染。只要两个节点直接连接,且其中至少一个节点受到恶意软件的感染,那么两个节点都将被恶意软件......
  • 2023-06-10:给定一个由 n 个节点组成的网络,用 n x n 个邻接矩阵 graph 表示 在节点网络
    2023-06-10:给定一个由n个节点组成的网络,用nxn个邻接矩阵graph表示在节点网络中,只有当graph[i][j]=1时,节点i能够直接连接到另一个节点j。一些节点initial最初被恶意软件感染。只要两个节点直接连接,且其中至少一个节点受到恶意软件的感染,那么两个节点都将被恶意......