All Nodes Distance K in Binary Tree

Updated on 15 May, 2025
All Nodes Distance K in Binary Tree header image

Problem Statement

In this problem, you are provided with the root of a binary tree, and you are tasked with finding the values of all nodes that are exactly 'k' units of distance from a specified target node. The distance is measured in terms of the number of edges between two nodes in the tree. You need to return these values as an array, and the order of values in the resulting array does not matter. This requires understanding both the structure of the tree and how to measure distances within it efficiently.

Examples

Example 1

Input:

root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, k = 2

Output:

[7,4,1]
Explanation: The nodes that are a distance 2 from the target node (with value 5) have values 7, 4, and 1.

Example 2

Input:

root = [1], target = 1, k = 3

Output:

[]

Constraints

  • The number of nodes in the tree is in the range [1, 500].
  • 0 <= Node.val <= 500
  • All the values Node.val are unique.
  • target is the value of one of the nodes in the tree.
  • 0 <= k <= 1000

Approach and Intuition

To solve the problem efficiently, understanding the tree's structure and utilizing a breadth-first search (BFS) or depth-first search (DFS) strategy can be very effective. Here's a simple approach based on BFS:

  1. Convert the Tree to a Graph Representation:

    • Since a binary tree is a special case of a graph, you can consider transforming the tree into a graph where nodes point to their parent and children. This reformation helps in easy traversal in multiple directions (upwards towards the parent and downwards to the children).
  2. Find the Target Node in the Tree:

    • Traverse the tree to find the node that has the value equal to target. During this traversal, record the parent nodes for access during the BFS.
  3. Perform BFS Starting from the Target Node:

    • Initialize a queue and push the target node into it along with a distance of 0.
    • While the queue is not empty, pop the node from the queue:
      • Check the distance:
        • If it equals k, record the node's value.
        • If it is greater than k, stop further traversal from this path.
      • If less than k, push the neighboring nodes (children and parent) onto the queue with incremented distance.
  4. Return the Collected Values:

    • The solution nodes are those collected at distances exactly equal to k. They are then returned as an array.

Edge Cases

  • If the target node equals null, or k is 0, handle these according to the tree's structure — either by returning the target node itself if k=0, or an empty list if no valid moves are available.

Considerations Given Constraints

  • Given the constraints, such as the maximum number of nodes being 500 and the unique value property, the approach remains efficient.
  • Large k values, especially those greater than the tree's maximum height, simply result in an empty result since no node will satisfy the distance condition.

In the provided examples:

  • Example 1 outlines a common scenario with multiple levels, and the function correctly identifies three nodes at distance 2 from the target node (value 5).
  • Example 2 shows a situation where the tree is a single node, and the distance k exceeds the potential maximum distance in the tree, resulting in an empty array as expected.

Solutions

  • C++
  • Java
  • Python
cpp
class Solution {
public:
    vector<int> findNodesAtDistanceK(TreeNode* root, TreeNode* target, int k) {
        unordered_map<int, vector<int>> adjacencyList;

        // Generate adjacency list using DFS
        constructGraph(root, nullptr, adjacencyList);

        vector<int> result;
        unordered_set<int> seen;

        // Set up BFS using a queue starting from the target node
        queue<pair<int, int>> queueBFS;
        queueBFS.push({target->val, 0});
        seen.insert(target->val);

        while (!queueBFS.empty()) {
            auto currentNode = queueBFS.front();
            queueBFS.pop();

            int currentValue = currentNode.first;
            int currentDistance = currentNode.second;

            if (currentDistance == k) {
                result.push_back(currentValue);
                continue;
            }
            for (int neighbor : adjacencyList[currentValue]) {
                if (seen.find(neighbor) == seen.end()) {
                    seen.insert(neighbor);
                    queueBFS.push({neighbor, currentDistance + 1});
                }
            }
        }
        return result;
    }

private:
    void constructGraph(TreeNode* node, TreeNode* parent,
                        unordered_map<int, vector<int>>& adjList) {
        if (node != nullptr && parent != nullptr) {
            adjList[node->val].push_back(parent->val);
            adjList[parent->val].push_back(node->val);
        }

        if (node != nullptr && node->left != nullptr) {
            constructGraph(node->left, node, adjList);
        }

        if (node != nullptr && node->right != nullptr) {
            constructGraph(node->right, node, adjList);
        }
    }
};

The provided C++ code is a solution to find all nodes at a distance K in a binary tree. This solution uses a combination of Depth-First Search (DFS) to construct an adjacency list representation of the tree and Breadth-First Search (BFS) to find nodes at the specified distance from the target node.

Here's a breakdown of how this code works:

  • Construct the TreeNode graph into an adjacency list:
    • The constructGraph function is used to convert the binary tree into a graph by creating an adjacency list. It recursively navigates through each node and its children, linking nodes to their parents, thereby allowing bidirectional traversal later in BFS.
  • Traverse the adjacency list using BFS to find the result:
    • Initialize a queue for BFS starting from the target node’s value with a distance of 0.
    • Use a set to keep track of visited nodes to prevent reprocessing the same node.
    • For each node processed in the BFS, check the distance. If it equals k, add the node’s value to the result.
    • Add all unvisited neighboring nodes into the BFS queue with incremented distance.

Steps to leverage the code effectively:

  1. Define a binary tree using the TreeNode structure provided in your setup.
  2. Have values filled and the links between nodes correctly represented as a typical binary tree.
  3. Instantiate the Solution class and call findNodesAtDistanceK with the root of the tree, the target node, and the integer k to denote distance.
  4. The return of this function will be a vector of integers representing the values of nodes that are at distance k from the target node.

Ensure that the binary tree and target node are correctly assigned values to avoid null references. The approach is efficient in terms of space and time complexities, making use of both DFS for graphical conversion and BFS for targeted search, suitable for trees where nodes have unique values.

java
class Solution {

    public List<Integer> nodesAtDistanceK(TreeNode root, TreeNode target, int k) {
        Map<Integer, List<Integer>> adjList = new HashMap<>();
        buildGraph(root, null, adjList);

        List<Integer> result = new ArrayList<>();
        Set<Integer> seen = new HashSet<>();
        Queue<int[]> q = new LinkedList<>();

        // Initialize queue with target node and distance 0
        q.add(new int[] { target.val, 0 });
        seen.add(target.val);

        // Process the queue
        while (!q.isEmpty()) {
            int[] nodeInfo = q.poll();
            int nodeId = nodeInfo[0], dist = nodeInfo[1];

            // If reached required distance, collect the node
            if (dist == k) {
                result.add(nodeId);
                continue;
            }

            // Traverse the neighbors
            for (int neighbor : adjList.getOrDefault(nodeId, new ArrayList<>())) {
                if (!seen.contains(neighbor)) {
                    seen.add(neighbor);
                    q.add(new int[] { neighbor, dist + 1 });
                }
            }
        }

        return result;
    }

    // Helper to build graph from binary tree
    private void buildGraph(TreeNode node, TreeNode parent, Map<Integer, List<Integer>> adjList) {
        if (node != null && parent != null) {
            adjList.putIfAbsent(node.val, new ArrayList<>());
            adjList.putIfAbsent(parent.val, new ArrayList<>());
            adjList.get(node.val).add(parent.val);
            adjList.get(parent.val).add(node.val);
        }

        if (node != null && node.left != null) {
            buildGraph(node.left, node, adjList);
        }

        if (node != null && node.right != null) {
            buildGraph(node.right, node, adjList);
        }
    }
}

Find all nodes at a specified distance k from a target node in a binary tree using this Java function. The solution leverages Breadth-First Search (BFS) and a graph representation of the binary tree to efficiently determine nodes at the desired distance. Here’s a concise guide on how this implementation works:

  • Build Adjacency List: Convert the binary tree into a graph using an adjacency list for effective BFS traversal. This is accomplished by the buildGraph method, which establishes relationships between each node and its parent ensuring all connections (both child-to-parent and parent-to-child) are reflected in the adjacency list.

  • Initialize BFS Variables: Use a queue to manage the BFS nodes along with their current distances from the target. Also, utilize a set to track visited nodes to prevent redundant processing.

  • BFS Traversal:

    1. Start with the target node and initiate its distance as 0.
    2. Process each node from the queue:
      • If the node's distance from the target equals k, add the node to the result list.
      • Otherwise, explore unvisited neighboring nodes, update their distances, and enqueue them.
  • Return Result: After processing all possible paths within the distance k, return the list of nodes that meet the criteria.

This method ensures an efficient traversal by avoiding re-visits and leveraging direct access patterns made possible by the adjacency list graph representation. Whether the tree is sparse or dense, this approach systematically checks each level up to the distance k from the target node, ensuring a comprehensive and optimal solution.

python
class Solution:
    def nodesAtDistanceK(self, root: TreeNode, target: TreeNode, k: int) -> List[int]:
        node_map = collections.defaultdict(list)

        # Construct a graph from the binary tree nodes
        def construct_graph(current, parent):
            if current and parent:
                node_map[current.val].append(parent.val)
                node_map[parent.val].append(current.val)
            if current.left:
                construct_graph(current.left, current)
            if current.right:
                construct_graph(current.right, current)

        construct_graph(root, None)

        result = []
        seen = set([target.val])

        # BFS initialization with target node
        bfs_queue = collections.deque([(target.val, 0)])
        while bfs_queue:
            node_val, dist = bfs_queue.popleft()

            # Check if current node is at the required distance k
            if dist == k:
                result.append(node_val)
                continue

            # Explore all adjacent nodes
            for adjacent in node_map[node_val]:
                if adjacent not in seen:
                    seen.add(adjacent)
                    bfs_queue.append((adjacent, dist + 1))

        return result

To solve the problem of finding all nodes at distance K in a binary tree using Python, follow these key steps using the provided classes and methods:

  1. Start by creating a graph representation of the binary tree. Use a defaultdict to store each node's value and its adjacent nodes. This setup helps in transforming the tree structure into a graph where each node knows its adjacent nodes, facilitating easier traversal.

  2. Implement a helper function construct_graph that takes current and parent nodes as parameters:

    • Add the current node's value as a key to the node_map and append the parent's value to the list of its values, and vice versa.
    • Recursively call construct_graph for the left and right children of the current node.
  3. Initialize the BFS traversal:

    • Begin by marking the target node's value as seen and add it to a queue with its distance initialized to 0.
  4. Continue with the BFS traversal:

    • Dequeue a node and check its distance. If it matches K, add the node's value to the result list.
    • For each adjacent node that hasn't been visited (not in seen), mark it as seen and enqueue it along with the updated distance.
  5. The function eventually returns a list of node values that are at distance K from the target node.

This technique efficiently locates nodes at a specified distance in a binary tree by leveraging graph traversal methods, specifically BFS, making it optimal for diverse tree structures.

Comments

No comments yet.