|
| 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 | + |
| 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