Closest Nodes Queries in a Binary Search Tree

medium binary search tree binary search inorder traversal

Problem

Given the root of a binary search tree and an array of queries, return for each query q a pair [min, max]: min is the largest value in the tree that is ≤ q (its predecessor), and max is the smallest value in the tree that is ≥ q (its successor). Use -1 when such a value does not exist.

Inputtree = [6,2,13,1,4,9,15], queries = [2,5,16]
Output[[2,2],[4,6],[15,-1]]
Sorted values are [1,2,4,6,9,13,15]. For 5 the predecessor is 4 and the successor is 6; for 16 nothing is ≥ 16, so max = -1.

def closestNodes(root, queries):
    vals = []
    def inorder(node):
        if not node:
            return
        inorder(node.left)
        vals.append(node.val)
        inorder(node.right)
    inorder(root)
    ans = []
    for q in queries:
        lo, hi = 0, len(vals)
        while lo < hi:                 # smallest idx with vals[idx] >= q
            mid = (lo + hi) // 2
            if vals[mid] < q:
                lo = mid + 1
            else:
                hi = mid
        mx = vals[lo] if lo < len(vals) else -1
        mn = vals[lo] if lo < len(vals) and vals[lo] == q else \
             (vals[lo - 1] if lo > 0 else -1)
        ans.append([mn, mx])
    return ans
function closestNodes(root, queries) {
  const vals = [];
  (function inorder(node) {
    if (!node) return;
    inorder(node.left);
    vals.push(node.val);
    inorder(node.right);
  })(root);
  const ans = [];
  for (const q of queries) {
    let lo = 0, hi = vals.length;
    while (lo < hi) {                 // smallest idx with vals[idx] >= q
      const mid = (lo + hi) >> 1;
      if (vals[mid] < q) lo = mid + 1;
      else hi = mid;
    }
    const mx = lo < vals.length ? vals[lo] : -1;
    const mn = (lo < vals.length && vals[lo] === q)
      ? vals[lo] : (lo > 0 ? vals[lo - 1] : -1);
    ans.push([mn, mx]);
  }
  return ans;
}
List<List<Integer>> closestNodes(TreeNode root, List<Integer> queries) {
    List<Integer> vals = new ArrayList<>();
    inorder(root, vals);
    List<List<Integer>> ans = new ArrayList<>();
    for (int q : queries) {
        int lo = 0, hi = vals.size();
        while (lo < hi) {              // smallest idx with vals[idx] >= q
            int mid = (lo + hi) >>> 1;
            if (vals.get(mid) < q) lo = mid + 1;
            else hi = mid;
        }
        int mx = lo < vals.size() ? vals.get(lo) : -1;
        int mn = (lo < vals.size() && vals.get(lo) == q) ? vals.get(lo)
                 : (lo > 0 ? vals.get(lo - 1) : -1);
        ans.add(List.of(mn, mx));
    }
    return ans;
}
vector<vector<int>> closestNodes(TreeNode* root, vector<int>& queries) {
    vector<int> vals;
    function<void(TreeNode*)> inorder = [&](TreeNode* n) {
        if (!n) return;
        inorder(n->left);
        vals.push_back(n->val);
        inorder(n->right);
    };
    inorder(root);
    vector<vector<int>> ans;
    for (int q : queries) {
        int lo = lower_bound(vals.begin(), vals.end(), q) - vals.begin();
        int mx = lo < (int)vals.size() ? vals[lo] : -1;
        int mn = (lo < (int)vals.size() && vals[lo] == q) ? vals[lo]
                 : (lo > 0 ? vals[lo - 1] : -1);
        ans.push_back({mn, mx});
    }
    return ans;
}
Time: O(n + m·log n) Space: O(n)