返回介绍

solution / 1400-1499 / 1483.Kth Ancestor of a Tree Node / README

发布于 2024-06-17 01:03:19 字数 7060 浏览 0 评论 0 收藏 0

1483. 树节点的第 K 个祖先

English Version

题目描述

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

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

实现 TreeAncestor 类:

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

 

示例 1:

输入:
["TreeAncestor","getKthAncestor","getKthAncestor","getKthAncestor"]
[[7,[-1,0,0,1,1,2,2]],[3,1],[5,2],[6,3]]

输出:
[null,1,0,-1]

解释:
TreeAncestor treeAncestor = new TreeAncestor(7, [-1, 0, 0, 1, 1, 2, 2]);

treeAncestor.getKthAncestor(3, 1);  // 返回 1 ,它是 3 的父节点
treeAncestor.getKthAncestor(5, 2);  // 返回 0 ,它是 5 的祖父节点
treeAncestor.getKthAncestor(6, 3);  // 返回 -1 因为不存在满足要求的祖先节点

 

提示:

  • 1 <= k <= n <= 5 * 104
  • parent[0] == -1 表示编号为 0 的节点是根节点。
  • 对于所有的 0 < i < n0 <= parent[i] < n 总成立
  • 0 <= node < n
  • 至多查询 5 * 104

解法

方法一:动态规划 + 倍增

题目要我们寻找节点 $node$ 的第 $k$ 个祖先节点,如果暴力求解,需要从 $node$ 开始向上遍历 $k$ 次,时间复杂度为 $O(k)$,显然会超时。

我们可以使用动态规划,结合倍增的思想来处理。

我们定义 $p[i][j]$ 表示节点 $i$ 的第 $2^j$ 个祖先节点,即 $p[i][j]$ 表示节点 $i$ 向上走 $2^j$ 步的节点。那么我们可以得到状态转移方程:

$$ p[i][j] = p[p[i][j-1]][j-1] $$

即:要想找到节点 $i$ 的第 $2^j$ 个祖先节点,我们可以先找到节点 $i$ 的第 $2^{j-1}$ 个祖先节点,然后再找到该节点的第 $2^{j-1}$ 个祖先节点即可。所以,我们要找到每个节点的距离为 $2^j$ 的祖先节点,直到达到树的最大高度。

之后对于每次查询,我们可以把 $k$ 拆成二进制的表示形式,然后根据二进制中 $1$ 的位置,累计向上查询,最终得到节点 $node$ 的第 $k$ 个祖先节点。

时间复杂度方面,初始化为 $O(n \times \log n)$,查询为 $O(\log n)$。空间复杂度 $O(n \times \log n)$。其中 $n$ 为树的节点数。

相似题目:

class TreeAncestor:
  def __init__(self, n: int, parent: List[int]):
    self.p = [[-1] * 18 for _ in range(n)]
    for i, fa in enumerate(parent):
      self.p[i][0] = fa
    for j in range(1, 18):
      for i in range(n):
        if self.p[i][j - 1] == -1:
          continue
        self.p[i][j] = self.p[self.p[i][j - 1]][j - 1]

  def getKthAncestor(self, node: int, k: int) -> int:
    for i in range(17, -1, -1):
      if k >> i & 1:
        node = self.p[node][i]
        if node == -1:
          break
    return node


# Your TreeAncestor object will be instantiated and called as such:
# obj = TreeAncestor(n, parent)
# param_1 = obj.getKthAncestor(node,k)
class TreeAncestor {
  private int[][] p;

  public TreeAncestor(int n, int[] parent) {
    p = new int[n][18];
    for (var e : p) {
      Arrays.fill(e, -1);
    }
    for (int i = 0; i < n; ++i) {
      p[i][0] = parent[i];
    }
    for (int j = 1; j < 18; ++j) {
      for (int i = 0; i < n; ++i) {
        if (p[i][j - 1] == -1) {
          continue;
        }
        p[i][j] = p[p[i][j - 1]][j - 1];
      }
    }
  }

  public int getKthAncestor(int node, int k) {
    for (int i = 17; i >= 0; --i) {
      if (((k >> i) & 1) == 1) {
        node = p[node][i];
        if (node == -1) {
          break;
        }
      }
    }
    return node;
  }
}

/**
 * Your TreeAncestor object will be instantiated and called as such:
 * TreeAncestor obj = new TreeAncestor(n, parent);
 * int param_1 = obj.getKthAncestor(node,k);
 */
class TreeAncestor {
public:
  TreeAncestor(int n, vector<int>& parent) {
    p = vector<vector<int>>(n, vector<int>(18, -1));
    for (int i = 0; i < n; ++i) {
      p[i][0] = parent[i];
    }
    for (int j = 1; j < 18; ++j) {
      for (int i = 0; i < n; ++i) {
        if (p[i][j - 1] == -1) {
          continue;
        }
        p[i][j] = p[p[i][j - 1]][j - 1];
      }
    }
  }

  int getKthAncestor(int node, int k) {
    for (int i = 17; ~i; --i) {
      if (k >> i & 1) {
        node = p[node][i];
        if (node == -1) {
          break;
        }
      }
    }
    return node;
  }

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

/**
 * Your TreeAncestor object will be instantiated and called as such:
 * TreeAncestor* obj = new TreeAncestor(n, parent);
 * int param_1 = obj->getKthAncestor(node,k);
 */
type TreeAncestor struct {
  p [][18]int
}

func Constructor(n int, parent []int) TreeAncestor {
  p := make([][18]int, n)
  for i, fa := range parent {
    p[i][0] = fa
    for j := 1; j < 18; j++ {
      p[i][j] = -1
    }
  }
  for j := 1; j < 18; j++ {
    for i := range p {
      if p[i][j-1] == -1 {
        continue
      }
      p[i][j] = p[p[i][j-1]][j-1]
    }
  }
  return TreeAncestor{p}
}

func (this *TreeAncestor) GetKthAncestor(node int, k int) int {
  for i := 17; i >= 0; i-- {
    if k>>i&1 == 1 {
      node = this.p[node][i]
      if node == -1 {
        break
      }
    }
  }
  return node
}

/**
 * Your TreeAncestor object will be instantiated and called as such:
 * obj := Constructor(n, parent);
 * param_1 := obj.GetKthAncestor(node,k);
 */
class TreeAncestor {
  private p: number[][];

  constructor(n: number, parent: number[]) {
    const p = new Array(n).fill(0).map(() => new Array(18).fill(-1));
    for (let i = 0; i < n; ++i) {
      p[i][0] = parent[i];
    }
    for (let j = 1; j < 18; ++j) {
      for (let i = 0; i < n; ++i) {
        if (p[i][j - 1] === -1) {
          continue;
        }
        p[i][j] = p[p[i][j - 1]][j - 1];
      }
    }
    this.p = p;
  }

  getKthAncestor(node: number, k: number): number {
    for (let i = 17; i >= 0; --i) {
      if (((k >> i) & 1) === 1) {
        node = this.p[node][i];
        if (node === -1) {
          break;
        }
      }
    }
    return node;
  }
}

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文