Skip to content

Commit dcce248

Browse files
1483 - Kth Ancestor of a Tree Node.md
1 parent 6d71973 commit dcce248

File tree

1 file changed

+151
-0
lines changed

1 file changed

+151
-0
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
---
2+
id: kth-ancestor-of-a-tree node
3+
title: Kth Ancestor of a Tree Node
4+
sidebar_label: 1483 Kth Ancestor of a Tree Node
5+
tags:
6+
- Java
7+
- Binary Search
8+
- Dynamic Programming
9+
- Tree
10+
- Depth-First Search
11+
- Breadth-First Search
12+
- Design
13+
description: "This document provides a solution where we Find the kth ancestor of a given node."
14+
---
15+
16+
## Problem
17+
18+
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 $i^{\text{th}}$ node. The root of the tree is node $0$. Find the $k^{\text{th}}$ ancestor of a given node.
19+
20+
The $k^{\text{th}}$ ancestor of a tree node is the $k^{\text{th}}$ node in the path from that node to the root node.
21+
22+
Implement the $TreeAncestor$ class:
23+
24+
- $TreeAncestor(int n, int[] parent)$ Initializes the object with the number of nodes in the tree and the parent array.
25+
26+
- $int getKthAncestor(int node, int k)$ return the $k^{\text{th}}$ ancestor of the given node node. If there is no such ancestor, return $-1$.
27+
28+
### Examples
29+
30+
**Example 1:**
31+
32+
![image](https://github.com/vivekvardhan2810/codeharborhub.github.io/assets/91594529/c96383bd-e0bb-494d-8112-226686ab1832)
33+
34+
**Input:** ["TreeAncestor", "getKthAncestor", "getKthAncestor", "getKthAncestor"]
35+
[[7, [-1, 0, 0, 1, 1, 2, 2]], [3, 1], [5, 2], [6, 3]]
36+
37+
**Output:** [null, 1, 0, -1]
38+
39+
**Explanation:**
40+
41+
TreeAncestor treeAncestor = new TreeAncestor(7, [-1, 0, 0, 1, 1, 2, 2]);
42+
43+
treeAncestor.getKthAncestor(3, 1); // returns 1 which is the parent of 3
44+
45+
treeAncestor.getKthAncestor(5, 2); // returns 0 which is the grandparent of 5
46+
47+
treeAncestor.getKthAncestor(6, 3); // returns -1 because there is no such ancestor
48+
49+
### Constraints
50+
51+
- $1 <= k <= n <= 5 * 10^4$
52+
- $parent.length == n$
53+
- $parent[0] == -1$
54+
- $0 <= parent[i] < n$ for all $0 < i < n$
55+
- $0 <= node < n$
56+
- There will be at most $5 * 10^4$ queries.
57+
---
58+
59+
## Approach
60+
61+
To solve the problem, we need to understand the nature of the allowed moves:
62+
63+
1. **Binary Lifting Setup**:
64+
65+
- Calculate the maximum power of 2 needed, which is $\log_2(n)$. This represents the maximum number of jumps we need to consider.
66+
67+
- Create a 2D array **'dp'** where **'dp[i][j]'** represents the $2^j$-th ancestor of node i.
68+
69+
2. **Preprocessing**:
70+
71+
- Initialize **'dp[i][0]'** with the parent of node i.
72+
73+
- Fill in the rest of the **'dp'** table using dynamic programming. For each power j, compute **'dp[i][j]'** using **'dp[i][j-1]'**. Specifically, **'dp[i][j]'** is $2^j$-th ancestor of node i, which is the $2^j-1$-th ancestor of node i.
74+
75+
3. **Query Processing**:
76+
77+
- For each query to find the 𝑘-th ancestor of a node, use the binary representation of 𝑘. For each bit that is set in 𝑘, jump accordingly using the **'dp'** table.
78+
79+
- If at any point the ancestor becomes $'-1'$, return $'-1'$.
80+
81+
## Solution for Kth Ancestor of a Tree Node
82+
83+
- The goal is to find the $k^{\text{th}}$ ancestor of a node efficiently. A naive approach would involve iterating up the tree one node at a time, which would be too slow for large values of k. Instead, we use a technique called "binary lifting".
84+
85+
- Binary lifting allows us to jump in powers of two, which significantly speeds up the process. By preprocessing the tree, we can answer each query in logarithmic time.
86+
87+
#### Code in Java
88+
89+
```java
90+
import java.util.*;
91+
92+
class TreeAncestor {
93+
private int[][] dp;
94+
private int maxPower;
95+
96+
public TreeAncestor(int n, int[] parent) {
97+
maxPower = (int) (Math.log(n) / Math.log(2)) + 1;
98+
dp = new int[n][maxPower];
99+
100+
for (int i = 0; i < n; i++) {
101+
dp[i][0] = parent[i];
102+
}
103+
104+
for (int j = 1; j < maxPower; j++) {
105+
for (int i = 0; i < n; i++) {
106+
int midAncestor = dp[i][j - 1];
107+
if (midAncestor != -1) {
108+
dp[i][j] = dp[midAncestor][j - 1];
109+
} else {
110+
dp[i][j] = -1;
111+
}
112+
}
113+
}
114+
}
115+
116+
public int getKthAncestor(int node, int k) {
117+
for (int j = 0; j < maxPower; j++) {
118+
if ((k & (1 << j)) > 0) {
119+
node = dp[node][j];
120+
if (node == -1) {
121+
return -1;
122+
}
123+
}
124+
}
125+
return node;
126+
}
127+
128+
public static void main(String[] args) {
129+
TreeAncestor treeAncestor = new TreeAncestor(7, new int[]{-1, 0, 0, 1, 1, 2, 2});
130+
System.out.println(treeAncestor.getKthAncestor(3, 1)); // returns 1
131+
System.out.println(treeAncestor.getKthAncestor(5, 2)); // returns 0
132+
System.out.println(treeAncestor.getKthAncestor(6, 3)); // returns -1
133+
}
134+
}
135+
```
136+
137+
### Complexity Analysis
138+
139+
#### Time Complexity: $O(n log n)$
140+
141+
> **Reason**: Initializing the dp array requires iterating through all nodes for each power of 2 up to log𝑛, where as coming to query it involves checking up to log 𝑛 bits in the binary representation of 𝑘 and making jumps accordingly.
142+
143+
#### Space Complexity: $O(log n)$
144+
145+
> **Reason**: The space complexity is $O(log n)$, The **'dp'** table requires 𝑛 × log𝑛, where 𝑛 is the number of nodes and log𝑛 is the maximum power of 2 we consider.
146+
147+
# References
148+
149+
- **LeetCode Problem:** [Kth Ancestor of a Tree Node](https://leetcode.com/problems/kth-ancestor-of-a-tree-node/description/)
150+
- **Solution Link:** [Kth Ancestor of a Tree Node Solution on LeetCode](https://leetcode.com/problems/kth-ancestor-of-a-tree-node/solutions/)
151+
- **Authors LeetCode Profile:** [Vivek Vardhan](https://leetcode.com/u/vivekvardhan43862/)

0 commit comments

Comments
 (0)