Closest Binary Search Tree Value

Problem I

Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target.

Note

Given target value is a floating point. You are guaranteed to have only one unique value in the BST that is closest to the target.

Solution

public class ClosestBSTValue {
    double min = Double.MAX_VALUE;
    TreeNode closest = null;

    public int closestValue(TreeNode root, double target) {
        if (root == null) {
            return Integer.MAX_VALUE;
        }
        helper(root, target);
        return closest.val;
    }

    private void helper(TreeNode node, double target) {
        if (node == null)
            return;
        if (Math.abs((double) node.val - target) < min) {
            min = Math.abs((double) node.val - target);
            closest = node;
        }

        if((double) node.val > target) {
            helper(node.left, target);
        }else{
            helper(node.right, target);
        }
    }
}

Problem II

Given a non-empty binary search tree and a target value, find k values in the BST that are closest to the target.

Note

  • Given target value is a floating point.
  • You may assume k is always valid, that is:k ≤ total nodes.
  • You are guaranteed to have only one unique set of k values in the BST that are closest to the target.

Follow up

Assume that the BST is balanced, could you solve it in less than runtime (where n = total nodes)?

Hint

  • Consider implement these two helper functions:
    • getPredecessor(N), which returns the next smaller node to N.
    • getSuccessor(N), which returns the next larger node to N.
  • Try to assume that each node has a parent pointer, it makes the problem much easier.
  • Without parent pointer we just need to keep track of the path from the root to the current node using a stack.
  • You would need two stacks to track the path in finding predecessor and successor node separately.

Think #1

  • The straight-forward solution would be to use a heap.
  • We just treat the BST just as a usual array and do a in-order traverse.
  • Then we compare the current element with the minimum element in the heap, the same as top k problem.

Solution #1

class Solution {
    private PriorityQueue<Integer> minPQ;
    private int count = 0;
    public List<Integer> closestKValues(TreeNode root, double target, int k) {
        minPQ = new PriorityQueue<;Integer>(k);
        List<Integer> result = new ArrayList<Integer>();

        inorderTraverse(root, target, k);

        // Dump the pq into result list
        for (Integer elem : minPQ) {
            result.add(elem);
        }

        return result;
    }

    private void inorderTraverse(TreeNode root, double target, int k) {
        if (root == null) {
            return;
        }
        // recursive way
        inorderTraverse(root.left, target, k);

        if (count < k) {
            minPQ.offer(root.val);
        } else {
            if (Math.abs((double) root.val - target) < Math.abs((double) minPQ.peek() - target)) {
                minPQ.poll();
                minPQ.offer(root.val);
            }
        }
        count++;

        inorderTraverse(root.right, target, k);
    }
}

Think #2

  • Stack solution to replace the recursion way for inorder traversal
  • Maintain a queue with K size, compare the head of queue and current value to make sure the minimum difference.
  • When the head of queue has less difference to target than current node, stop iterate.

Solution #2

    public List<Integer> closestKValuesII(TreeNode root, double target, int k) {
        Queue<Integer> values = new LinkedList<>();

        // build inorder traversal
        Stack<TreeNode> stack = new Stack<>();
        do {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();

            // compare and insert to the queue
            if(values.size() < k) {
                values.add(root.val);
            }else{
                int pop = values.peek();
                if(Math.abs((double)root.val - target) < Math.abs((double)pop - target)) {
                    values.poll();
                    values.add(root.val);
                }else
                    break;
            }

            if(root.right !=null) {
                root = root.right;
            }else
                root = null;
        } while (!stack.isEmpty());
        return new ArrayList<Integer>(values);
    }

results matching ""

    No results matching ""