Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,8 @@
* [Test Cyclically Shifted Array](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/search/binary_search/cyclically_shifted_array/test_cyclically_shifted_array.py)
* Find Closest Number
* [Test Find Closest Number](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/search/binary_search/find_closest_number/test_find_closest_number.py)
* Find Closest Value
* [Test Find Closest Value](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/search/binary_search/find_closest_value/test_find_closest_value.py)
* Find First In Duplicate List
* [Test Find First In Duplicates](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/search/binary_search/find_first_in_duplicate_list/test_find_first_in_duplicates.py)
* Find Fixed Number
Expand Down
40 changes: 40 additions & 0 deletions datastructures/trees/binary/search_tree/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,46 @@ def find_second_largest(self) -> BinaryTreeNode:

return current

def find_closest_value_in_bst(self, target: T) -> Optional[BinaryTreeNode]:
"""
Finds the closest value in the binary search tree to the given target value.

Args:
target T: Value to search for
Returns:
Node with the closest value to the target
"""
# edge case for empty nodes, if none is provided, we can't find a value that is close to the target
if not self.root:
return None

# if the node's data is the target, exit early by returning it
if self.root.data == target:
return self.root

# this keeps track of the minimum on both the left and the right
closest_node = self.root
min_diff = abs(target - self.root.data)
current = self.root

# while the queue is not empty, we pop off nodes from the queue and check for their values
while current:
current_diff = abs(target - self.root.data)

if current_diff < min_diff:
min_diff = current_diff
closest_node = current

if current.data == target:
return current

if target < current.data:
current = current.left
else:
current = current.right

return closest_node

def range_sum(self, low: int, high: int):
"""
returns the sum of datas of all nodes with a data in the range [low, high].
Expand Down
5 changes: 2 additions & 3 deletions puzzles/search/binary_search/find_closest_number/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Find the Closest Number

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
target number. We will be making use of a binary search to solve this problem, so make sure that you have gone through
the previous lesson.
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
target number. We will be making use of a binary search to solve this problem.

The array may contain duplicate values and negative numbers.

Expand Down
43 changes: 43 additions & 0 deletions puzzles/search/binary_search/find_closest_value/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Find Closest Value in BST

Write a function that takes in a Binary Search Tree (BST) and a target integer
value and returns the closest value to that target value contained in the BST.

You can assume that there will only be one closest value.

Each <span>BST</span> node has an integer <span>value</span>, a
<span>left</span> child node, and a <span>right</span> child node. A node is
said to be a valid <span>BST</span> node if and only if it satisfies the BST
property: its <span>value</span> is strictly greater than the values of every
node to its left; its <span>value</span> is less than or equal to the values
of every node to its right; and its children nodes are either valid
<span>BST</span> nodes themselves or <span>None</span> / <span>null</span>.

Sample Input:

```text
tree = 10
/ \
5 15
/ \ / \
2 5 13 22
/ \
1 14
target = 12
```

Sample output: 13

## Hints

- Try traversing the BST node by node, all the while keeping track of the node with the value closest to the target value.
Calculating the absolute value of the difference between a node's value and the target value should allow you to
check if that node is closer than the current closest one.
- Make use of the BST property to determine what side of any given node has values close to the target value and is
therefore worth exploring.
- What are the advantages and disadvantages of solving this problem iteratively as opposed to recursively?

## Optimal Space & Time Complexity

Average: O(log(n)) time | O(1) space where n is the number of nodes in the tree
BST Worst: O(n) time | O(1) space where n is the number of nodes in the tree
35 changes: 35 additions & 0 deletions puzzles/search/binary_search/find_closest_value/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from typing import Optional
from datastructures.trees.binary.search_tree import BinaryTreeNode


def find_closest_value_in_bst(node: BinaryTreeNode, target: int) -> Optional[int]:
# edge case for empty nodes, if none is provided, we can't find a value that is close to the target
if not node:
return None

# if the node's data is the target, exit early by returning it
if node.data == target:
return node.data

# this keeps track of the minimum on both the left and the right
closest_value = node.data
min_diff = abs(target - node.data)
current = node

# while the queue is not empty, we pop off nodes from the queue and check for their values
while current:
current_diff = abs(target - current.data)

if current_diff < min_diff:
min_diff = current_diff
closest_value = current.data

if current.data == target:
return current.data

if target < current.data:
current = current.left
else:
current = current.right

return closest_value
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import unittest
from datastructures.trees.binary.search_tree import BinaryTreeNode
from . import find_closest_value_in_bst


class FindClosestValueTestCases(unittest.TestCase):
def test_something(self):
root = BinaryTreeNode(
data=10,
left=BinaryTreeNode(data=5,
left=BinaryTreeNode(
data=2,
left=BinaryTreeNode(data=1),
right=BinaryTreeNode(data=5))
),
right=BinaryTreeNode(data=15,
left=BinaryTreeNode(
data=13,
right=BinaryTreeNode(
data=14,
right=BinaryTreeNode(data=22)
)
))
)
expected = 13
actual = find_closest_value_in_bst(root, target=12)
self.assertEqual(expected, actual)


if __name__ == '__main__':
unittest.main()
Loading