Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
You are given the root of a binary tree with n nodes. Each node is assigned a unique value from 1 to n. You are also given an array queries of size m.
You have to perform m independent queries on the tree where in the ith query you do the following:
queries[i] from the tree. It is guaranteed that queries[i] will not be equal to the value of the root.Return an array answer of size m where answer[i] is the height of the tree after performing the ith query.
Note:
Example 1:
Input: root = [1,3,4,2,null,6,5,null,null,null,null,null,7], queries = [4] Output: [2] Explanation: The diagram above shows the tree after removing the subtree rooted at node with value 4. The height of the tree is 2 (The path 1 -> 3 -> 2).
Example 2:
Input: root = [5,8,9,2,1,3,7,4,6], queries = [3,2,4,8] Output: [3,2,3,2] Explanation: We have the following queries: - Removing the subtree rooted at node with value 3. The height of the tree becomes 3 (The path 5 -> 8 -> 2 -> 4). - Removing the subtree rooted at node with value 2. The height of the tree becomes 2 (The path 5 -> 8 -> 1). - Removing the subtree rooted at node with value 4. The height of the tree becomes 3 (The path 5 -> 8 -> 2 -> 6). - Removing the subtree rooted at node with value 8. The height of the tree becomes 2 (The path 5 -> 9 -> 3).
Constraints:
n.2 <= n <= 1051 <= Node.val <= nm == queries.length1 <= m <= min(n, 104)1 <= queries[i] <= nqueries[i] != root.valProblem summary: You are given the root of a binary tree with n nodes. Each node is assigned a unique value from 1 to n. You are also given an array queries of size m. You have to perform m independent queries on the tree where in the ith query you do the following: Remove the subtree rooted at the node with the value queries[i] from the tree. It is guaranteed that queries[i] will not be equal to the value of the root. Return an array answer of size m where answer[i] is the height of the tree after performing the ith query. Note: The queries are independent, so the tree returns to its initial state after each query. The height of a tree is the number of edges in the longest simple path from the root to some node in the tree.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Tree
[1,3,4,2,null,6,5,null,null,null,null,null,7] [4]
[5,8,9,2,1,3,7,4,6] [3,2,4,8]
maximum-depth-of-binary-tree)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2458: Height of Binary Tree After Subtree Removal Queries
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
private Map<TreeNode, Integer> d = new HashMap<>();
private int[] res;
public int[] treeQueries(TreeNode root, int[] queries) {
f(root);
res = new int[d.size() + 1];
d.put(null, 0);
dfs(root, -1, 0);
int m = queries.length;
int[] ans = new int[m];
for (int i = 0; i < m; ++i) {
ans[i] = res[queries[i]];
}
return ans;
}
private void dfs(TreeNode root, int depth, int rest) {
if (root == null) {
return;
}
++depth;
res[root.val] = rest;
dfs(root.left, depth, Math.max(rest, depth + d.get(root.right)));
dfs(root.right, depth, Math.max(rest, depth + d.get(root.left)));
}
private int f(TreeNode root) {
if (root == null) {
return 0;
}
int l = f(root.left), r = f(root.right);
d.put(root, 1 + Math.max(l, r));
return d.get(root);
}
}
// Accepted solution for LeetCode #2458: Height of Binary Tree After Subtree Removal Queries
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func treeQueries(root *TreeNode, queries []int) (ans []int) {
d := map[*TreeNode]int{}
var f func(*TreeNode) int
f = func(root *TreeNode) int {
if root == nil {
return 0
}
l, r := f(root.Left), f(root.Right)
d[root] = 1 + max(l, r)
return d[root]
}
f(root)
res := make([]int, len(d)+1)
var dfs func(*TreeNode, int, int)
dfs = func(root *TreeNode, depth, rest int) {
if root == nil {
return
}
depth++
res[root.Val] = rest
dfs(root.Left, depth, max(rest, depth+d[root.Right]))
dfs(root.Right, depth, max(rest, depth+d[root.Left]))
}
dfs(root, -1, 0)
for _, v := range queries {
ans = append(ans, res[v])
}
return
}
# Accepted solution for LeetCode #2458: Height of Binary Tree After Subtree Removal Queries
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def treeQueries(self, root: Optional[TreeNode], queries: List[int]) -> List[int]:
def f(root):
if root is None:
return 0
l, r = f(root.left), f(root.right)
d[root] = 1 + max(l, r)
return d[root]
def dfs(root, depth, rest):
if root is None:
return
depth += 1
res[root.val] = rest
dfs(root.left, depth, max(rest, depth + d[root.right]))
dfs(root.right, depth, max(rest, depth + d[root.left]))
d = defaultdict(int)
f(root)
res = [0] * (len(d) + 1)
dfs(root, -1, 0)
return [res[v] for v in queries]
// Accepted solution for LeetCode #2458: Height of Binary Tree After Subtree Removal Queries
// Rust example auto-generated from java reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (java):
// // Accepted solution for LeetCode #2458: Height of Binary Tree After Subtree Removal Queries
// /**
// * Definition for a binary tree node.
// * public class TreeNode {
// * int val;
// * TreeNode left;
// * TreeNode right;
// * TreeNode() {}
// * TreeNode(int val) { this.val = val; }
// * TreeNode(int val, TreeNode left, TreeNode right) {
// * this.val = val;
// * this.left = left;
// * this.right = right;
// * }
// * }
// */
// class Solution {
// private Map<TreeNode, Integer> d = new HashMap<>();
// private int[] res;
//
// public int[] treeQueries(TreeNode root, int[] queries) {
// f(root);
// res = new int[d.size() + 1];
// d.put(null, 0);
// dfs(root, -1, 0);
// int m = queries.length;
// int[] ans = new int[m];
// for (int i = 0; i < m; ++i) {
// ans[i] = res[queries[i]];
// }
// return ans;
// }
//
// private void dfs(TreeNode root, int depth, int rest) {
// if (root == null) {
// return;
// }
// ++depth;
// res[root.val] = rest;
// dfs(root.left, depth, Math.max(rest, depth + d.get(root.right)));
// dfs(root.right, depth, Math.max(rest, depth + d.get(root.left)));
// }
//
// private int f(TreeNode root) {
// if (root == null) {
// return 0;
// }
// int l = f(root.left), r = f(root.right);
// d.put(root, 1 + Math.max(l, r));
// return d.get(root);
// }
// }
// Accepted solution for LeetCode #2458: Height of Binary Tree After Subtree Removal Queries
function treeQueries(root: TreeNode | null, queries: number[]): number[] {
const ans: number[] = [];
const levels: Map<number, [number, number][]> = new Map();
const valToLevel = new Map<number, number>();
const dfs = (node: TreeNode | null, level = 0): number => {
if (!node) return level - 1;
const max = Math.max(dfs(node.left, level + 1), dfs(node.right, level + 1));
if (!levels.has(level)) {
levels.set(level, []);
}
levels.get(level)?.push([max, node.val]);
valToLevel.set(node.val, level);
return max;
};
dfs(root, 0);
for (const [_, l] of levels) {
l.sort(([a], [b]) => b - a);
}
for (const q of queries) {
const level = valToLevel.get(q)!;
const maxes = levels.get(level)!;
if (maxes.length === 1) {
ans.push(level - 1);
} else {
const [val0, max0, max1] = [maxes[0][1], maxes[0][0], maxes[1][0]];
const max = val0 === q ? max1 : max0;
ans.push(max);
}
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
BFS with a queue visits every node exactly once — O(n) time. The queue may hold an entire level of the tree, which for a complete binary tree is up to n/2 nodes = O(n) space. This is optimal in time but costly in space for wide trees.
Every node is visited exactly once, giving O(n) time. Space depends on tree shape: O(h) for recursive DFS (stack depth = height h), or O(w) for BFS (queue width = widest level). For balanced trees h = log n; for skewed trees h = n.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Recursive traversal assumes children always exist.
Usually fails on: Leaf nodes throw errors or create wrong depth/path values.
Fix: Handle null/base cases before recursive transitions.