19. K Closest Values
β GFG solution to the K Closest Values in BST problem: find k values closest to target using iterative inorder traversal and two-pointer technique. π
The problem can be found at the following link: π Question Link
π§© Problem Description
Given the root of a Binary Search Tree, a target value, and an integer k
, your task is to find the k values in the BST that are closest to the target.
The closest value is determined by the minimum absolute difference from the target. If two values have the same absolute difference, choose the smaller value. The target may or may not be present in the BST.
π Examples
Example 1
Input: root = [20, 8, 22, 4, 12, N, N, N, N, 10, 14], target = 17, k = 3
Output: [14, 20, 12]
Explanation: Absolute difference of 17 with 14 and 20 is 3 each, but we choose
the smaller value (14) first. Then 12 and 22 both have absolute difference 5,
so we choose the smaller value (12).
Example 2
Input: root = [5, 4, 8, 1], target = 5, k = 2
Output: [5, 4]
Explanation: The absolute difference of 5 with itself is 0, and with 4 is 1.
π Constraints
$1 \le \text{number of nodes, k} \le 10^4$
$1 \le \text{nodeβdata, target} \le 10^4$
β
My Approach
The optimal approach uses Iterative Inorder Traversal combined with Binary Search and Two-Pointer Technique:
Iterative Inorder + Binary Search + Two Pointers
Inorder Traversal:
Use iterative inorder traversal with a stack to collect all BST values in sorted order.
This gives us a sorted array without recursion overhead.
Find Starting Position:
Use
lower_bound
(binary search) to find the position closest to or just greater than the target.Adjust position to the closest element by comparing distances.
Two-Pointer Expansion:
Initialize two pointers:
left
at the found position andright
at position + 1.Compare absolute differences from target for elements at both pointers.
When distances are equal, prefer the smaller value (left pointer).
Pick k closest elements by expanding in both directions.
Handle Edge Cases:
Check boundary conditions when left pointer goes below 0 or right pointer exceeds array size.
Ensure tie-breaking favors smaller values.
π Time and Auxiliary Space Complexity
Expected Time Complexity: O(n + log n + k), where n is the number of nodes in the BST. The inorder traversal takes O(n) time, binary search takes O(log n), and extracting k closest elements takes O(k) time.
Expected Auxiliary Space Complexity: O(n + h), where n is for storing the inorder traversal and h is the height of the tree for the stack used during iterative traversal. In the worst case, h can be O(n) for a skewed tree, but for a balanced BST, h = O(log n).
π§βπ» Code (C++)
class Solution {
public:
vector<int> getKClosest(Node* root, int target, int k) {
vector<int> in;
stack<Node*> s;
Node* curr = root;
while (curr || !s.empty()) {
while (curr) s.push(curr), curr = curr->left;
curr = s.top(); s.pop();
in.push_back(curr->data);
curr = curr->right;
}
int n = in.size(), pos = lower_bound(in.begin(), in.end(), target) - in.begin();
if (pos > 0 && (pos == n || abs(in[pos - 1] - target) <= abs(in[pos] - target))) pos--;
vector<int> res;
int l = pos, r = pos + 1;
while (k--) {
if (r >= n || (l >= 0 && abs(in[l] - target) <= abs(in[r] - target)))
res.push_back(in[l--]);
else
res.push_back(in[r++]);
}
return res;
}
};
β Code (Java)
class Solution {
public ArrayList<Integer> getKClosest(Node root, int target, int k) {
ArrayList<Integer> in = new ArrayList<>();
Stack<Node> s = new Stack<>();
Node curr = root;
while (curr != null || !s.isEmpty()) {
while (curr != null) {
s.push(curr);
curr = curr.left;
}
curr = s.pop();
in.add(curr.data);
curr = curr.right;
}
int n = in.size(), l = 0, r = n - 1, pos = 0;
while (l <= r) {
int m = l + (r - l) / 2;
if (in.get(m) <= target) {
pos = m;
l = m + 1;
} else r = m - 1;
}
ArrayList<Integer> res = new ArrayList<>();
l = pos; r = pos + 1;
while (k-- > 0) {
if (r >= n || (l >= 0 && Math.abs(in.get(l) - target) <= Math.abs(in.get(r) - target)))
res.add(in.get(l--));
else
res.add(in.get(r++));
}
return res;
}
}
π Code (Python)
class Solution:
def getKClosest(self, root, target, k):
in_order, stack, curr = [], [], root
while curr or stack:
while curr:
stack.append(curr)
curr = curr.left
curr = stack.pop()
in_order.append(curr.data)
curr = curr.right
n, l, r, pos = len(in_order), 0, len(in_order) - 1, 0
while l <= r:
m = (l + r) // 2
if in_order[m] <= target:
pos, l = m, m + 1
else:
r = m - 1
res, l, r = [], pos, pos + 1
while k:
if r >= n or (l >= 0 and abs(in_order[l] - target) <= abs(in_order[r] - target)):
res.append(in_order[l])
l -= 1
else:
res.append(in_order[r])
r += 1
k -= 1
return res
π§ Contribution and Support
For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: π¬ Any Questions?. Let's make this learning journey more collaborative!
β If you find this helpful, please give this repository a star! β
πVisitor Count
Last updated