leetcode每日一题

92 阅读2分钟

[1483. 树节点的第 K 个祖先]

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

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

实现 TreeAncestor 类:

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

思路如下

这个问题可以通过预处理父节点数组来解决,以便在查询时能够快速找到第k个祖先节点。我们可以使用一个二维数组dp,其中dp[i][j]表示节点i的第2^j个祖先。这样,我们可以在O(logk)的时间内找到节点的第k个祖先。 首先,我们需要初始化dp数组。对于每个节点i,它的第1个祖先(即2^0)就是parent[i]。然后,我们可以使用动态规划的方法来填充dp数组的其余部分。对于每个节点i和每个j>0,节点i的第2^j个祖先dp[i][j]就是它的第2^(j-1)个祖先的第2^(j-1)个祖先,即dp[dp[i][j-1]][j-1]。 然后,当我们需要查询节点node的第k个祖先时,我们可以将k表示为二进制形式,然后从高位到低位依次找到每个为1的位对应的祖先。

代码实现:

class TreeAncestor {
    int[][] dp;

    public TreeAncestor(int n, int[] parent) {
        int m = (int)(Math.log(n) / Math.log(2)) + 1;
        dp = new int[n][m];
        for (int i = 0; i < n; i++) {
            dp[i][0] = parent[i];
        }
        for (int j = 1; j < m; j++) {
            for (int i = 0; i < n; i++) {
                if (dp[i][j - 1] != -1) {
                    dp[i][j] = dp[dp[i][j - 1]][j - 1];
                } else {
                    dp[i][j] = -1;
                }
            }
        }
    }

    public int getKthAncestor(int node, int k) {
        int m = dp[0].length;
        for (int j = m - 1; j >= 0; j--) {
            if ((k & (1 << j)) != 0) {
                node = dp[node][j];
                if (node == -1) {
                    return -1;
                }
            }
        }
        return node;
    }