Closest Binary Search Tree Value II

Updated on 13 May, 2025
Closest Binary Search Tree Value II header image

Problem Statement

The task is rooted in a common problem involving binary search trees (BSTs), where one needs to find the k closest values to a given target number within the tree. Working with BSTs is beneficial due to their properties of ordered data, which can potentially simplify searching and sorting operations. Given a target value and an integer k, the goal is to accurately identify the k nearest numbers to the target from the numbers present in the BST. The output does not necessitate a specific order, hence any sequence containing the correct values is valid. The problem assures that there is a unique set of k values closest to the target, which simplifies the task by avoiding ambiguity in determining which numbers are closest when distances are identical.

Examples

Example 1

Input:

root = [4,2,5,1,3], target = 3.714286, k = 2

Output:

[4,3]

Example 2

Input:

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

Output:

[1]

Constraints

  • The number of nodes in the tree is n.
  • 1 <= k <= n <= 104.
  • 0 <= Node.val <= 109
  • -109 <= target <= 109

Approach and Intuition

  1. BST Traversal:

    • A straightforward approach could involve an in-order traversal of the BST, which inherently produces a sorted list of elements. This sorted list can then be used to find the k elements nearest to the target.
  2. Optimized Search Using a Heap:

    • Rather than sorting the complete list of elements, one can maintain a heap (or priority queue) of size k to store the closest elements encountered during a tree traversal. If we use a max-heap, we can compare the absolute difference of the current node value with the target. If this difference is less than the maximum difference in the heap, we replace the maximum element in the heap with the current element.
    • This approach ensures that at any point, the heap contains the k closest elements, and since we are employing a max-heap, the element with the largest difference (least close to the target) can be efficiently removed if needed.
  3. Balanced Traversal Algorithm:

    • To further improve, particularly if k is much smaller than n, a more directed search using the properties of BST can be deployed. Starting from the root node, one can decide to move left or right depending on how the current node's value compares to the target. This reduces the number of nodes to consider since half of the tree can potentially be disregarded at each step based on whether the target value is less than or greater than the node’s value.

This problem lays the foundation for understanding some fundamental operations with binary trees, such as traversal techniques and dynamic data storage using heaps, while also requiring efficient decision-making based on the tree's properties and the problem's constraints.

Solutions

  • Java
  • Python
java
class Solution {
    public List<Integer> findClosestElements(TreeNode root, double target, int k) {
        Deque<Integer> result = new LinkedList<>();
        traverseInOrder(root, result, k, target);
        return new ArrayList<>(result);
    }

    public void traverseInOrder(TreeNode current, Deque<Integer> result, int k, double target) {
        if (current == null) {
            return;
        }

        traverseInOrder(current.left, result, k, target);
        result.add(current.val);
        if (result.size() > k) {
            if (Math.abs(target - result.peekFirst()) <= Math.abs(target - result.peekLast())) {
                result.removeLast();
                return;
            } else {
                result.removeFirst();
            }
        }

        traverseInOrder(current.right, result, k, target);
    }
}

This Java solution addresses the problem of finding the k closest values to a given target in a Binary Search Tree (BST). It utilizes an in-order traversal to leverage the BST properties, ensuring elements are visited in ascending order. The solution employs a Deque to store the closest values and dynamically adjusts its contents based on their distance to the target.

Follow these steps to understand the solution implementation:

  1. Declare a findClosestElements method that takes a TreeNode representing the root of the tree, a double target value, and an integer k indicating the number of closest nodes required. It initializes a Deque<Integer> to hold the results and invokes the traverseInOrder method.

  2. Implement the traverseInOrder method to perform an in-order traversal of the BST. This method accepts the current node, the results deque, k, and the target value as parameters.

  3. In traverseInOrder, check if the current node is null to handle the base case of the recursion.

  4. Recursively visit the left child of the current node.

  5. Add the current node's value to the deque. Subsequently, if the deque contains more than k elements, compare the absolute differences of the deque's first and last elements with the target to decide which element to remove. This ensures that only the closest k elements to the target are retained.

  6. Finally, recursively visit the right child.

  7. Return the contents of the deque converted into an array list as the result of the findClosestElements method.

This method effectively maintains the closest k values during the traversal and uses the properties of the Deque to efficiently manage which values to keep or discard based on their proximity to the target value.

python
class Solution:
    def findClosestKValues(self, root: TreeNode, target: float, k: int) -> List[int]:
        def traverse(node, buffer):
            if not node:
                return
            
            traverse(node.left, buffer)
            buffer.append(node.val)
            if len(buffer) > k:
                if abs(target - buffer[0]) <= abs(target - buffer[-1]):
                    buffer.pop()
                    return
                else:
                    buffer.popleft()
                    
            traverse(node.right, buffer)
        
        buffer = deque()
        traverse(root, buffer)
        return list(buffer)

This Python solution finds the k closest values to a given target in a Binary Search Tree (BST). Here’s a concise explanation of how the code achieves this:

  • A nested function traverse is defined within the findClosestKValues method. This function uses in-order traversal of the BST to access nodes in a non-decreasing order.
  • A deque is utilized as a buffer to store the values closest to the target. The buffer size is maintained to not exceed k.
  • During the in-order traversal, after adding each node's value to the buffer:
    • If the buffer size exceeds k, the code compares the absolute difference between the target and elements at both ends of the buffer.
    • Depending on which difference is smaller, the corresponding element is removed from the buffer (either the earliest or the latest added element).
  • At the end of the traversal, the buffer will contain the k closest values to the target, which are then returned as a list.

This method effectively manages a balance between checking each BST node and maintaining a list of the closest k values, making optimal use of tree properties and data structure operations.

Comments

No comments yet.