Solving Leetcode Interviews in Seconds with AI: Kth Ancestor of a Tree Node
Introduction
In this blog post, we will explore how to solve the LeetCode problem "1483" using AI. LeetCode is a popular platform for preparing for coding interviews, and with the help of AI tools like Chatmagic, we can generate solutions quickly and efficiently - helping you pass the interviews and get the job offer without having to study for months.
Problem Statement
You are given a tree with n nodes numbered from 0 to n - 1 in the form of a parent array parent where parent[i] is the parent of ith node. The root of the tree is node 0. Find the kth ancestor of a given node. The kth ancestor of a tree node is the kth node in the path from that node to the root node. Implement the TreeAncestor class: TreeAncestor(int n, int[] parent) Initializes the object with the number of nodes in the tree and the parent array. int getKthAncestor(int node, int k) return the kth ancestor of the given node node. If there is no such ancestor, return -1. Example 1: Input ["TreeAncestor", "getKthAncestor", "getKthAncestor", "getKthAncestor"] [[7, [-1, 0, 0, 1, 1, 2, 2]], [3, 1], [5, 2], [6, 3]] Output [null, 1, 0, -1] Explanation TreeAncestor treeAncestor = new TreeAncestor(7, [-1, 0, 0, 1, 1, 2, 2]); treeAncestor.getKthAncestor(3, 1); // returns 1 which is the parent of 3 treeAncestor.getKthAncestor(5, 2); // returns 0 which is the grandparent of 5 treeAncestor.getKthAncestor(6, 3); // returns -1 because there is no such ancestor Constraints: 1 <= k <= n <= 5 104 parent.length == n parent[0] == -1 0 <= parent[i] < n for all 0 < i < n 0 <= node < n There will be at most 5 104 queries.
Explanation
Here's the solution to find the kth ancestor of a node in a tree, along with an explanation of the approach, complexity analysis, and the Python code.
Binary Lifting: The core idea is to precompute the 2i-th ancestor for each node. This is done using dynamic programming. We store these ancestors in a 2D array
ancestors, whereancestors[node][i]represents the 2i-th ancestor ofnode.Efficient Querying: To find the k-th ancestor of a node, we decompose
kinto its binary representation. For each bit set ink, we "jump" to the corresponding precomputed ancestor. This allows us to find the k-th ancestor in logarithmic time.Initialization: The
ancestorsarray is initialized using the parent array.ancestors[node][0]is simply the parent of the node. The remaining entries are computed iteratively:ancestors[node][i] = ancestors[ancestors[node][i-1]][i-1]. This means the 2i-th ancestor ofnodeis the 2(i-1)-th ancestor of the 2(i-1)-th ancestor ofnode.Runtime & Storage Complexity:
- Time Complexity: Initialization: O(n log n), Query: O(log k) ≈ O(log n) since k <= n.
- Space Complexity: O(n log n) for the
ancestorsarray.
Code
class TreeAncestor:
def __init__(self, n: int, parent: list[int]):
self.n = n
self.max_level = n.bit_length() # ceil(log2(n)) + 1
self.ancestors = [[-1] * self.max_level for _ in range(n)]
for i in range(n):
self.ancestors[i][0] = parent[i]
for j in range(1, self.max_level):
for i in range(n):
if self.ancestors[i][j-1] != -1:
self.ancestors[i][j] = self.ancestors[self.ancestors[i][j-1]][j-1]
def getKthAncestor(self, node: int, k: int) -> int:
for i in range(self.max_level):
if (k >> i) & 1:
node = self.ancestors[node][i]
if node == -1:
return -1
return node