Skip to content

Commit 57fad82

Browse files
committed
feat(puzzles, datastructures): find closest value in bst
1 parent 3c5ac87 commit 57fad82

File tree

5 files changed

+164
-3
lines changed

5 files changed

+164
-3
lines changed

datastructures/trees/binary/search_tree/__init__.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,52 @@ def find_second_largest(self) -> BinaryTreeNode:
219219

220220
return current
221221

222+
def find_closest_value_in_bst(self, target: T) -> Optional[BinaryTreeNode]:
223+
"""
224+
Finds the closest value in the binary search tree to the given target value.
225+
226+
Args:
227+
target T: Value to search for
228+
Returns:
229+
Node with the closest value to the target
230+
"""
231+
# edge case for empty nodes, if none is provided, we can't find a value that is close to the target
232+
if not self.root:
233+
return None
234+
235+
# if the node's data is the target, exit early by returning it
236+
if self.root.data == target:
237+
return self.root
238+
239+
# this keeps track of the minimum on both the left and the right
240+
min_diff = min_diff_left = min_diff_right = float("inf")
241+
closest_value = None
242+
fifo_queue = FifoQueue()
243+
fifo_queue.enqueue(self.root)
244+
245+
# while the queue is not empty, we pop off nodes from the queue and check for their values
246+
while not fifo_queue.is_empty():
247+
current_node = fifo_queue.dequeue()
248+
249+
min_diff_left = abs(target - current_node.data)
250+
min_diff_right = abs(target - current_node.data)
251+
252+
if min_diff_left < min_diff:
253+
min_diff = min_diff_left
254+
closest_value = current_node
255+
256+
if min_diff_right < min_diff:
257+
min_diff = min_diff_right
258+
closest_value = current_node
259+
260+
if current_node.left:
261+
fifo_queue.enqueue(current_node.left)
262+
263+
if current_node.right:
264+
fifo_queue.enqueue(current_node.right)
265+
266+
return closest_value
267+
222268
def range_sum(self, low: int, high: int):
223269
"""
224270
returns the sum of datas of all nodes with a data in the range [low, high].

puzzles/search/binary_search/find_closest_number/README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
# Find the Closest Number
22

3-
we will be given a sorted array and a target number. Our goal is to find a number in the array that is closest to the
4-
target number. We will be making use of a binary search to solve this problem, so make sure that you have gone through
5-
the previous lesson.
3+
We will be given a sorted array and a target number. Our goal is to find a number in the array that is closest to the
4+
target number. We will be making use of a binary search to solve this problem.
65

76
The array may contain duplicate values and negative numbers.
87

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Find Closest Value in BST
2+
3+
Write a function that takes in a Binary Search Tree (BST) and a target integer
4+
value and returns the closest value to that target value contained in the BST.
5+
6+
You can assume that there will only be one closest value.
7+
8+
Each <span>BST</span> node has an integer <span>value</span>, a
9+
<span>left</span> child node, and a <span>right</span> child node. A node is
10+
said to be a valid <span>BST</span> node if and only if it satisfies the BST
11+
property: its <span>value</span> is strictly greater than the values of every
12+
node to its left; its <span>value</span> is less than or equal to the values
13+
of every node to its right; and its children nodes are either valid
14+
<span>BST</span> nodes themselves or <span>None</span> / <span>null</span>.
15+
16+
Sample Input:
17+
18+
```text
19+
tree = 10
20+
/ \
21+
5 15
22+
/ \ / \
23+
2 5 13 22
24+
/ \
25+
1 14
26+
target = 12
27+
```
28+
29+
Sample output: 13
30+
31+
## Hints
32+
33+
- Try traversing the BST node by node, all the while keeping track of the node with the value closest to the target value.
34+
Calculating the absolute value of the difference between a node's value and the target value should allow you to
35+
check if that node is closer than the current closest one.
36+
- Make use of the BST property to determine what side of any given node has values close to the target value and is
37+
therefore worth exploring.
38+
- What are the advantages and disadvantages of solving this problem iteratively as opposed to recursively?
39+
40+
## Optimal Space & Time Complexity
41+
42+
Average: O(log(n)) time | O(1) space where n is the number of nodes in the tree
43+
BST Worst: O(n) time | O(1) space where n is the number of nodes in the tree
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from typing import Optional
2+
from queue import Queue
3+
from datastructures.trees.binary.search_tree import BinaryTreeNode
4+
5+
6+
def find_closest_value_in_bst(node: BinaryTreeNode, target: int) -> Optional[int]:
7+
# edge case for empty nodes, if none is provided, we can't find a value that is close to the target
8+
if not node:
9+
return None
10+
11+
# if the node's data is the target, exit early by returning it
12+
if node.data == target:
13+
return node.data
14+
15+
# this keeps track of the minimum on both the left and the right
16+
min_diff = min_diff_left = min_diff_right = float("inf")
17+
closest_value = None
18+
fifo_queue = Queue()
19+
fifo_queue.put(node)
20+
21+
# while the queue is not empty, we pop off nodes from the queue and check for their values
22+
while not fifo_queue.empty():
23+
current_node = fifo_queue.get()
24+
25+
min_diff_left = abs(target - current_node.data)
26+
min_diff_right = abs(target - current_node.data)
27+
28+
if min_diff_left < min_diff:
29+
min_diff = min_diff_left
30+
closest_value = current_node.data
31+
32+
if min_diff_right < min_diff:
33+
min_diff = min_diff_right
34+
closest_value = current_node.data
35+
36+
if current_node.left:
37+
fifo_queue.put(current_node.left)
38+
39+
if current_node.right:
40+
fifo_queue.put(current_node.right)
41+
42+
return closest_value
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import unittest
2+
from datastructures.trees.binary.search_tree import BinaryTreeNode
3+
from . import find_closest_value_in_bst
4+
5+
6+
class FindClosestValueTestCases(unittest.TestCase):
7+
def test_something(self):
8+
root = BinaryTreeNode(
9+
data=10,
10+
left=BinaryTreeNode(data=5,
11+
left=BinaryTreeNode(
12+
data=2,
13+
left=BinaryTreeNode(data=1),
14+
right=BinaryTreeNode(data=5))
15+
),
16+
right=BinaryTreeNode(data=15,
17+
left=BinaryTreeNode(
18+
data=13,
19+
right=BinaryTreeNode(
20+
data=14,
21+
right=BinaryTreeNode(data=22)
22+
)
23+
))
24+
)
25+
expected = 13
26+
actual = find_closest_value_in_bst(root, target=12)
27+
self.assertEqual(expected, actual)
28+
29+
30+
if __name__ == '__main__':
31+
unittest.main()

0 commit comments

Comments
 (0)