All Nodes Distance K in Binary Tree

MediumTrees · Graph BFS/DFS🧩 Graph DFSLeetCode #863 ↗Updated

Problem

You get the root of a binary tree with unique values, a node target inside it and an integer k. Return the values of every node whose distance from target is exactly k edges, where paths may go up through parents as well as down. Any order is accepted.
Inputroot = [3,5,1,6,2,0,8,null,null,7,4], target = 5, k = 2Output[7,4,1]
Inputroot = [1], target = 1, k = 3Output[]

1 ≤ nodes ≤ 500  ·  0 ≤ Node.val ≤ 500, all distinct  ·  target is in the tree  ·  0 ≤ k ≤ 1000

Try it yourself

Java
class Solution {
    public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
A tree is just an undirected graph whose “up” edges are hidden. Either expose them (parent map, then BFS k rings out from target) or let the recursion report how far below each ancestor the target sits and search the other side of that ancestor at the remaining depth.
PatternGraph DFS

Instinct Connected regions, all paths, reachability, cloning or 2-colouring a graph or grid: dive from a node, mark it, recurse into unvisited neighbours.

Memory hack Mark before you march: go deep, paint as you go, and back up only when every door is already painted.

Open the Graph DFS guide →

Approaches

Brute ForceRoot Paths + LCA Distance per Node

Time O(n · h) → O(n²)Space O(n)

The distance between two nodes is |pathA| + |pathB| - 2·c, where the paths start at the root and c is the length of their shared prefix (which ends at the LCA). Compute the target's root path once, then, for every node, find its root path and test whether the distance equals k.

Java
public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
    List<TreeNode> targetPath = new ArrayList<>();
    findPath(root, target, targetPath);
    List<TreeNode> all = new ArrayList<>();
    collect(root, all);
    List<Integer> res = new ArrayList<>();
    for (TreeNode node : all) {
        List<TreeNode> path = new ArrayList<>();
        findPath(root, node, path);
        int common = 0; // shared prefix length, ends at the LCA
        while (common < path.size() && common < targetPath.size()
                && path.get(common) == targetPath.get(common)) common++;
        if (path.size() + targetPath.size() - 2 * common == k) res.add(node.val);
    }
    return res;
}
private boolean findPath(TreeNode cur, TreeNode goal, List<TreeNode> path) {
    if (cur == null) return false;
    path.add(cur);
    if (cur == goal || findPath(cur.left, goal, path) || findPath(cur.right, goal, path)) {
        return true;
    }
    path.remove(path.size() - 1); // dead end: backtrack
    return false;
}
private void collect(TreeNode node, List<TreeNode> all) {
    if (node == null) return;
    all.add(node);
    collect(node.left, all);
    collect(node.right, all);
}

Pure tree reasoning with no graph conversion, but each node re-searches the tree.

At a glance

LevelApproachTimeSpace
Brute ForceRoot Paths + LCA Distance per NodeO(n · h) → O(n²)O(n)
BetterParent Map + BFS from TargetO(n)O(n)
OptimalSingle DFS Returning Distance to TargetO(n)O(h)
Common pitfalls
  • Only searching downward from target — misses nodes reached via the parent.
  • No seen set in the BFS → bouncing between a node and its parent forever.
  • In the DFS, searching the same child the target came from — double counts nodes.
Interview tips
  • Say “treat the tree as an undirected graph” first — it unlocks the BFS idea.
  • Handle k = 0 (just the target) and k larger than the tree height.
  • Offer the map-free DFS as a follow-up when asked to cut extra space.
Pattern
Tree → graph (parent links) + BFS rings → distances measured in any direction from a node inside a tree.
My notes saved in this browser