Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
Build a binary tree from the 1-indexed child-index array (row i lists node i's left and right children; −1 = no child; node 1 is the root at depth 1). For each query k, swap the left and right children of every node whose depth is a multiple of k (depths k, 2k, 3k, …), then record the inorder traversal. The crucial detail: swaps are CUMULATIVE — keep mutating one tree across queries, never rebuild. Build is O(n); each query is O(n) to swap by depth 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 where depth % k == 0), and produce an inorder traversal — while remembering swaps accumulate across queries.
Where candidates slip
Rebuilding/resetting the tree between queries (treating each independently), off-by-one in depth (root at depth 0 vs 1), or mis-mapping the 1-based index array to node objects.
How to stand out
Separate the three concerns cleanly — build once, swap-by-depth per query, inorder per query — and explicitly note swaps are cumulative so you mutate a single shared tree; mention iterative inorder for deep skewed trees.
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, run a normal inorder traversal to collect the values. Do NOT 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 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 (exchange the pointers; values don't move). 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 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 keep applying swaps — the second example (k=1 then k=1 flips 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 then 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 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 an 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. 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 mishandling the maxDepth bound.
- 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 — 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 — 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 problem3Mis-mapping the 1-based index array
Row i−1 of the array describes node i. Using indexes[i] for node i shifts every node's children by one, producing a wrong tree.
Explore the code comparisonHide the code comparison
Mis-mapping the 1-based index array
Row i−1 of the array describes node i. Using indexes[i] for node i shifts every node's children by one, producing a wrong tree.
Don't write this
l, r = indexes[i] # off by one for 1-based node iWrite this instead
l, r = indexes[i - 1] # row i-1 holds node i's childrenRevise
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
def swap_at_depth(node, depth, k):
if node is None: return
if depth % k == 0: node.left, node.right = node.right, node.left
swap_at_depth(node.left, depth + 1, k)
swap_at_depth(node.right, depth + 1, k)
# per query k: swap_at_depth(root, 1, k); record inorder(root)Rules to remember
- 1Indexing is 1-based: array row i (1..n) gives node i's children; the root is node 1 at depth 1.
- 2A child value of −1 means that child is absent (null).
- 3Swap children at depths k, 2k, 3k, … — the test is
depth % k == 0. - 4Swaps are cumulative across queries — mutate one persistent tree; never rebuild between queries.
- 5After each query emit the inorder traversal (Left, Node, Right).
Use this pattern when
- A tree given as an adjacency/index list you must materialize first
- Repeated structural mutations followed by a traversal report
- Any 'apply an operation by level/depth, then read the tree' simulation
- Mirror-by-level operations on a binary tree
Choose another pattern when
- A single static traversal with no mutation → just inorder, skip the swap machinery
- Mutations defined per-node, not per-depth → the depth % k shortcut doesn't apply
- Tree already given by pointers → skip the index-array construction
- Only the final tree shape matters, not each query's output → could fold queries
Interview takeaway
Swap Nodes stitches two skills: constructing a tree from a 1-indexed child-index array, and a depth-aware DFS that mutates then reports. The gotcha is that swaps accumulate — keep one tree and keep mutating it, reading inorder after each query.
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 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.