Binary Lifting 倍增算法

今天leetcode上看到一道算法题,了解了一下Binary Lifting,写篇博客详细介绍一下

题目描述:

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

请你设计并实现 getKthAncestor(int node, int k) 函数,函数返回节点 node 的第 k 个祖先节点。如果不存在这样的祖先节点,返回 -1 。

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-ancestor-of-a-tree-node

 就这?

class TreeAncestor {
    private int n;
    private int[] parent;

    public TreeAncestor(int n, int[] parent) {
        this.n=n;
        this.parent = parent;
    }
    
    public int getKthAncestor(int node, int k) {
        int ancestor = parent[node];
        for(int i=1;i<k&&ancestor!=-1;i++){
            ancestor = parent[ancestor];
        }
        return ancestor;
    }
}

/**
 * Your TreeAncestor object will be instantiated and called as such:
 * TreeAncestor obj = new TreeAncestor(n, parent);
 * int param_1 = obj.getKthAncestor(node,k);
 */

这不就解决了吗!

结果啪啪打脸

 看了一下答案,这道题正解是Binary Lifting,也就是倍增法

Binary Lifting的本质是动态规划,既然是动态规划,那么就要构建一个多维数组并且得到他的推导式。

二维数组dp[i][j],表示第i个节点的第2^{j}个祖先,那么推导式为:

dp[i][j]=dp[dp[i][j-1]][j-1]

初始条件为

dp[x][0]=parent[x], \ for\ \ x=0,1,2,...,n

然后依次得到dp[x][1]dp[x][2]dp[x][3]dp[x][4] 。。。

如果要查询节点i的第k个祖先,那么可以分解为

k=2^{0} \times {k_{0}} + 2^{1} \times {k_{1}} + ... + 2^{15} \times {k_{15}} , \ {k_{0}},{k_{1}}...,{k_{15}}=0,1   (假设k为16位整数)

例如,我们如果要查某个节点m的第11个祖先节点,那么11=0X1011,也就是2^{3}+2^{1}+2^{0},我们可以先查节点m的第2^{0}个祖先为r,再查r的第2^{1}个祖先为p,再查p的第2^{3}个祖先为q,那么q就是m的第11个祖先。最多只需要进行log(n)次查找,因此时间复杂度为log(n)。

  1. dp[m][0]=r
  2. dp[r][1]=p
  3. dp[p][3]=q

最后贴出代码

import java.util.Arrays;

public class TreeAncestor {
    private int[][] dp;

    public TreeAncestor(int n, int[] parent) {

        dp = new int[n][16];
        for (int[] a : dp) {
            Arrays.fill(a, -1);
        }
        for (int i = 0; i < n; i++) {
            dp[i][0] = parent[i];
        }
        for (int j = 1; j < 16; j++) {
            for (int i = 0; i < n; i++) {
                if (dp[i][j - 1] != -1) {
                    dp[i][j] = dp[dp[i][j - 1]][j - 1];
                }
            }
        }

    }

    public int getKthAncestor(int node, int k) {
        for (int i = 0; i < 16; i++) {
            if (((1 << i) & k) != 0) {
                node = dp[node][i];
            }
            if (node == -1) {
                break;
            }
        }
        return node;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值