LeetCode 1483. 树节点的第 K 个祖先***

具体思想:

谁抽到这道题,绝壁是祖上没积德倒霉催的;

普通hash存各个根节点过不了,会卡时间;

这道题思想是倍增思想;

也就是说,建立一个二维dp数组,dp[i][j]代表第i个节点的第 2 j 2^j 2j个节点;

转移方程为:
d p [ i ] [ j ] = d p [ d p [ i ] [ j − 1 ] [ j − 1 ] dp[i][j]=dp[dp[i][j-1][j-1] dp[i][j]=dp[dp[i][j1][j1]

难点在于怎么理解;

设想一下,如果j为零,则实际上是她的直接父节点,这是最基础的边界情况;

如果j=1,则要求计算其第 2 1 = 2 2^1=2 21=2个父节点;

按照状态转移方程为 d p [ d p [ i ] [ 0 ] ] [ 0 ] dp[dp[i][0]][0] dp[dp[i][0]][0],实际上就是其父节点的父节点;

如果j=2,则要求计算其第 2 2 = 4 2^2=4 22=4个父节点;

按照状态转移方程为 d p [ d p [ i ] [ 1 ] ] [ 1 ] dp[dp[i][1]][1] dp[dp[i][1]][1],即为第二个父节点的第二个父节点;

根据状态转移方程初始化,必定已经求过;

所以相当于两倍两倍向上搜;

但是还有一个难点,在于我们想要的节点未必是2的倍数,有可能是非2的倍数;

这里采用位运算思想;

对于第三个节点,二进制为11;

此时,诸位取得1,就可以得到是2的几次方;

例如:个位数1,取得其第1个父节点(2的0次方为1);

之后以该节点为起点搜寻第二个父节点(2的1次方为2,第二位1);

此时从最初点开始算就是第三个节点;

具体代码:

class TreeAncestor {
public:
    TreeAncestor(int n, vector<int>& parent) {
        int len=parent.size();
        dp.resize(len);
        for(int i=0;i<n;i++){
            dp[i].push_back(parent[i]);
        }
        int j=1;
        while(1){
            bool flag=true;//判定是不是所有节点的最终父节点都为-1;
            for(int i=0;i<n;i++){
                int t=dp[i][j-1]!=-1?dp[dp[i][j-1]][j-1]:-1;
                dp[i].push_back(t);
                if(t!=-1){
                    flag=false;
                }
            }
            if(flag)
                break;
            j++;
        }
    }
    
    int getKthAncestor(int node, int k) {
        if(k==0||node==-1)
            return node;
        int pos=ffs(k)-1;
        return pos < dp[node].size() ? getKthAncestor(dp[node][pos], k - (1 << pos)) : -1;
    }


private:
    vector<vector<int>>dp;
};

/**
 * Your TreeAncestor object will be instantiated and called as such:
 * TreeAncestor* obj = new TreeAncestor(n, parent);
 * int param_1 = obj->getKthAncestor(node,k);
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值