Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
Build the tree from the index array (node i's two children are given by row i, with −1 meaning no child; the root is node 1 at depth 1). For each query k, swap the left and right children of every node whose depth is a multiple of k (k, 2k, 3k, …), then print the inorder traversal of the resulting tree. Crucially, the swaps are CUMULATIVE — each query operates on the tree as left by the previous one. Build is O(n); each query is O(n) for the depth-swap DFS plus O(n) for inorder, so total O(n·q).
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you can build a tree from an index list with correct 1-based indexing, apply a depth-conditioned mutation (swap at depth % k == 0), and produce an inorder traversal — while remembering swaps accumulate.
Where candidates slip
Resetting the tree between queries (treating each query independently), off-by-one in depth (root at depth 0 vs 1), or mis-mapping the 1-based index array to nodes.
How to stand out
Separate the three concerns cleanly — build once, swap-by-depth per query, inorder per query — and explicitly note that swaps are cumulative so you mutate a single shared tree.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachFirst decision previewindex arrayfor each query kYesNoExplore the full treeCollapse the tree
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Build + Recursive Depth-Swap + Inorder (Canonical)
1Hint 1Explore hintHide hint
First materialize the tree: create n node objects (1-based) and wire each node's children from its row, treating −1 as null. The root is node 1.
2Hint 2Explore hintHide hint
For a query k, recurse from the root tracking depth (starting at 1). At any node where depth % k == 0, swap its left and right child pointers.
3Hint 3Explore hintHide hint
After the swap pass, do a normal inorder traversal to collect the values. Remember NOT to rebuild between queries — swaps accumulate.
A · Core idea
The problem decomposes into three independent pieces; solving each cleanly is what makes it manageable.
1. Build the tree (once). The input is a flat index list, not a pointer tree, so first reconstruct it. Create node objects for ids 1..n and store them so id i maps to nodes[i]. Then for each node i, read its row (L, R): if L != -1, set nodes[i].left = nodes[L]; same for the right. Node 1 is the root, at depth 1. Getting the 1-based mapping right — array index i-1 holds node i's children — is the most error-prone step.
2. Swap by depth (per query). For query k, traverse from the root carrying the current depth (root = 1). At every node, if depth % k == 0, swap its two child links (just exchange the pointers; you don't move values). Then recurse into both children at depth + 1. This touches depths k, 2k, 3k, … exactly. Swapping a node with a missing child simply swaps in a null — harmless.
3. Inorder after each query. Once the swaps for query k are applied, run a standard Left-Node-Right inorder to read off the current tree and store that as this query's answer.
The cumulative gotcha. Do not rebuild or undo between queries. Query 2 swaps on top of query 1's result. That's why we keep a single mutable tree and just keep applying swaps — the second example (k=1 then k=1 flips and then un-flips the root) only makes sense under cumulative semantics.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
indexes = [[2,3],[-1,4],[5,-1],[-1,-1],[-1,-1]], queries = [2]How to read it:Depth-2 nodes 2 and 3 swap children; inorder becomes 4 2 1 3 5.
4 2 1 3 5C · Code with teaching comments
Reference implementation previewimport java.util.*; class Node { int val; Node left;Explore the full codeHide the full code
D · Why it works and complexityO(n·q) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
Treat construction, mutation, and reporting as three separate functions. The only cross-cutting subtlety is that the mutation persists — one tree, repeatedly mutated — which is exactly what the 'swap and un-swap with two k=1 queries' example is testing.
ComplexityO(n·q) time, O(n) space — Building wires n nodes in O(n). Each query visits all n nodes for the swap pass and all n for inorder → O(n) per query, O(n·q) over q queries. Space is O(n) for the nodes plus O(h) recursion ≤ O(n).
E · Edge cases and pitfalls6k larger than the tree's depth — No node satisfies depth % k == 0 → tree unchanged, inorder is the original.Explore edge casesHide edge cases
Edge cases handled
k larger than the tree's depthNo node satisfies depth % k == 0 → tree unchanged, inorder is the original.Two consecutive k=1 queriesEvery depth swaps then swaps back → second inorder equals the original.Node with one child swappedThe existing child moves to the other side; the null moves too — still valid.
Pitfalls
- Rebuilding or resetting the tree between queries — breaks the cumulative semantics.
- Off-by-one on depth: root must be depth 1, so depth % k uses 1-based depth.
- Mis-mapping the 1-based index array (using indexes[i] for node i instead of indexes[i-1]).
Approach 2 of 2 · Optimal
Build + BFS Depth Buckets + Iterative Inorder
1Hint 1Explore hintHide hint
Run one BFS after building to record each node's depth (or group nodes by depth into buckets).
2Hint 2Explore hintHide hint
For a query k, iterate only the buckets at depths k, 2k, 3k, … and swap those nodes' children directly — no full DFS needed.
3Hint 3Explore hintHide hint
Use the explicit-stack iterative inorder so a deep, skewed tree can't overflow the call stack.
A · Core idea
Same three phases, but with two robustness tweaks that matter when the tree is deep.
Bucket nodes by depth. After building, run a BFS from the root tracking depth, pushing each node into buckets[depth]. This precomputes, once, which nodes live at each depth.
Swap via buckets. For a query k, you no longer need to walk the whole tree to find qualifying nodes — just iterate depths k, 2k, 3k, … and swap the child links of every node in those buckets. For small k this is still O(n) (k=1 hits every node), but it avoids the per-node modulo test and the recursion of the DFS version. The buckets stay valid across queries because swapping children never changes any node's depth.
Iterative inorder. A skewed input tree can be ~1024 nodes deep. Recursive inorder is usually fine at that depth, but the explicit-stack version (push the left spine, pop-visit, go right) removes any call-stack risk and is a good habit to demonstrate.
Still cumulative. As before, the single tree is mutated in place across queries; bucketing is just a faster way to locate the nodes to swap.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
indexes = [[2,3],[-1,4],[5,-1],[-1,-1],[-1,-1]], queries = [2]Interactive diagram
Depth buckets
bucketNodes grouped by depth once; query k swaps buckets at k, 2k, 3k…
4 2 1 3 5C · Code with teaching comments
D · Why it works and complexityO(n·q) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
Precomputing depth buckets turns 'find all nodes at depth multiples of k' into a direct lookup instead of a search, and pairs naturally with an iterative inorder to stay safe on deep trees. Depth never changes under child swaps, so the buckets are computed once and reused.
ComplexityO(n·q) time, O(n) space — BFS to bucket depths is O(n) once. Per query you still touch O(n) nodes in the worst case (k=1 swaps every node) plus O(n) iterative inorder → O(n·q). Space O(n) for buckets and the inorder stack.
E · Edge cases and pitfalls6k = maxDepth — Only the deepest bucket swaps (leaves) → usually no visible change.Explore edge casesHide edge cases
Edge cases handled
k = maxDepthOnly the deepest bucket swaps (leaves) → usually no visible change.k = 1Every bucket swaps — equivalent to mirroring the whole tree.Deeply skewed tree (~1024 deep)Iterative inorder avoids recursion-depth issues.
Pitfalls
- Recomputing buckets every query — unnecessary; depth is invariant, build them once.
- Looping depths from 0 instead of k, or using <= incorrectly on maxDepth.
- Forgetting swaps are cumulative even in the bucket version.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewimport java.util.*; public int[][] swapNodes(int[][] indexes, int[] queries) { int n = indexes.length; Node[] nodes = new Node[n + 1];Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Resetting the tree between queries
Swaps are cumulative. Rebuilding before each query yields wrong answers — e.g. two k=1 queries should flip then un-flip, which only works if the second query sees the first query's result.
Explore the code comparisonHide the code comparison
Resetting the tree between queries
Swaps are cumulative. Rebuilding before each query yields wrong answers — e.g. two k=1 queries should flip then un-flip, which only works if the second query sees the first query's result.
Don't write this
for k in queries:
root = build(indexes) # WRONG: rebuilds, loses cumulative swaps
swap_at_depth(root, 1, k)
result.append(inorder(root))Write this instead
root = build(indexes) # build ONCE
for k in queries:
swap_at_depth(root, 1, k) # mutate the same persistent tree
result.append(inorder(root))2Depth off-by-one
The root must be depth 1. Starting depth at 0 makes the root match depth % k == 0 for k=1 incorrectly and shifts every level, swapping the wrong depths.
Explore the code comparisonHide the code comparison
Depth off-by-one
The root must be depth 1. Starting depth at 0 makes the root match depth % k == 0 for k=1 incorrectly and shifts every level, swapping the wrong depths.
Don't write this
swapAtDepth(root, 0, k); // root treated as depth 0Write this instead
swapAtDepth(root, 1, k); // root is depth 1 per the problemRevise
Carry the pattern into the interview
Pattern to remember
Build tree from index list, then per-query depth-multiple child swaps + inorder
Code pattern to memorize
swapAtDepth(node, depth, k):
if node is null: return
if depth % k == 0: swap node.left, node.right
swapAtDepth(node.left, depth+1, k)
swapAtDepth(node.right, depth+1, k)
# per query k: swapAtDepth(root,1,k); then inorder(root)Rules to remember
- 1Indexing is 1-based: row i (1..n) lists the children of node i; the root is node 1 at depth 1.
- 2A child entry of −1 means that child is absent.
- 3Swap children at depths k, 2k, 3k, … — test
depth % k == 0. - 4Swaps are cumulative across queries — never rebuild the tree between queries.
- 5After each query, emit the inorder traversal (Left, Node, Right).
Use this pattern when
- A tree given as an adjacency/index list that you must materialize first
- Repeated structural mutations followed by a traversal report
- Any 'apply operation by level/depth, then read the tree' simulation
Choose another pattern when
- Single static traversal with no mutation → plain inorder, skip the swap machinery
- Mutations defined per-node not per-depth → can't use the depth % k shortcut
- Tree given by pointers already → skip the index-array construction step
Interview takeaway
This problem is two skills stitched together: constructing a tree from a 1-indexed child-index array, and a depth-aware DFS that mutates then reports. The cumulative-swap detail is the gotcha — keep one tree and keep mutating it.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternConstruct a tree from an index list, then run depth-conditioned mutations followed by a traversal report. The depth % k == 0 swap rule and cumulative semantics are the crux; depth buckets via BFS let you locate qualifying nodes directly, and an iterative inorder keeps deep trees safe. It blends tree construction, level/depth processing, and inorder traversal.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Tree: Inorder TraversalThe reporting half of this problem in isolation.
- Invert Binary TreeA k=1 swap is exactly mirroring the whole tree.
- Tree: Level Order TraversalThe BFS depth-bucketing here is the same level-by-level machinery.
- Construct Binary Tree from Preorder and InorderAnother build-the-tree-from-a-description warm-up.