forked from gitgik/algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
810 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
### Construct a Min Height BST | ||
Given an sorted array of integers, construct a min-height Binary Search Tree and return the root. All the BST rules apply. | ||
|
||
``` | ||
Sample input: | ||
[1, 2, 3, 5, 10, 12, 15, 20, 24] | ||
Sample output: | ||
10 | ||
/ \ | ||
2 15 | ||
/ \ / \ | ||
1 3 12 20 | ||
\ \ | ||
5 24 | ||
``` | ||
|
||
|
||
```python | ||
# First Approach | ||
def bst_constructor(A): | ||
"""Complexity | ||
O(N log N) time where N is the total number of elements in the array | ||
O(N) space | ||
""" | ||
if len(A) == 1: | ||
return BST(A[0]) | ||
|
||
return bst_helper(A, None, 0, len(A) - 1) | ||
|
||
def bst_helper(A, bst, start, end): | ||
# base case | ||
if start > end: | ||
return | ||
else: | ||
mid = (start + end) // 2 | ||
value_to_add = A[mid] | ||
if bst is None: | ||
# create the root | ||
bst = BST(value_to_add) | ||
else: | ||
bst.insert(value_to_add) | ||
bst_helper(A, bst, start, mid - 1) | ||
bst_helper(A, bst, mid + 1, end) | ||
return bst | ||
|
||
class BST: | ||
def __init__(self, value): | ||
self.value = value | ||
self.left = None | ||
self.right = None | ||
|
||
def insert(self, value): | ||
if value_to_add < self.value: | ||
if self.left is None: | ||
self.left = BST(value_to_add) | ||
else: | ||
self.left.insert(value_to_add) | ||
else: | ||
if self.right is None: | ||
self.right = BST(value_to_add) | ||
else: | ||
self.right.insert(value_to_add) | ||
|
||
``` | ||
|
||
|
||
```python | ||
# Second approach | ||
def bst_constructor(array): | ||
"""O(n) time | O(n) space""" | ||
return bst_constructor_helper(array, None, 0, len(array) - 1) | ||
|
||
def bst_constructor_helper(array, bst, start_index, end_index): | ||
if end_index < start_index: | ||
return | ||
else: | ||
mid_index = (start_index + end_index) // 2 | ||
new_bst_node = BST(array[mid_index]) | ||
if bst is None: | ||
bst = new_bst_node | ||
else: | ||
if array[mid_index] < bst.value: | ||
bst.left = BST(array[mid_index]) | ||
bst = bst.left | ||
else: | ||
bst.right = BST(array[mid_index]) | ||
bst = bst.right | ||
|
||
bst_constructor_helper(array, bst, start_index, mid_index - 1) | ||
bst_constructor_helper(array, bst, mid_index + 1, end_index) | ||
return bst | ||
``` | ||
|
||
|
||
```python | ||
# Third approach | ||
def bst_construct(A): | ||
"""O(n) time | O(n) space""" | ||
return bst_construct_helper(A, 0, len(A) - 1) | ||
|
||
def bst_construct_helper(A, start, end): | ||
# base case | ||
if end < start: | ||
return None | ||
mid = (start + end) // 2 | ||
bst = BST(A[mid]) | ||
bst.left = bst_construct_helper(A, start, mid - 1) | ||
bst.right = bst_construct_helper(A, mid + 1, end) | ||
return bst | ||
|
||
``` | ||
|
||
|
||
```python | ||
root = bst_construct([1, 2, 4]) | ||
print(f"{root.value}, {root.left.value}, {root.right.value}") | ||
``` | ||
|
||
2, 1, 4 | ||
|
||
|
||
|
||
```python | ||
root = bst_construct([1, 2, 3, 5, 10, 12, 15, 20, 24]) | ||
``` | ||
|
||
|
||
```python | ||
root.left.left.value | ||
``` | ||
|
||
|
||
|
||
|
||
1 | ||
|
||
|
||
|
||
|
||
```python | ||
# Fourth Appraoch: Cleanest | ||
def bstConstruct(A): | ||
if not A: | ||
return None | ||
mid = len(A) // 2 | ||
root = BST(A[mid]) | ||
root.left = bstConstruct(A[:mid]) | ||
root.right = bstConstruct(A[mid+1:]) | ||
return root | ||
``` | ||
|
||
|
||
```python | ||
root = bstConstruct([1, 2, 3, 4, 5, 6, 7]) | ||
|
||
def inOrder(node): | ||
if not node: | ||
return | ||
inOrder(node.left) | ||
print(node.value) | ||
inOrder(node.right) | ||
|
||
inOrder(root) | ||
``` | ||
|
||
1 | ||
2 | ||
3 | ||
4 | ||
5 | ||
6 | ||
7 | ||
|
||
|
||
|
||
```python | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
## BST implementation | ||
|
||
A node is said to be a BST node if and only if it satisfies the BST property: | ||
- its value is greater than all the node values to its left; | ||
- its values is less than the values of every node to its right, | ||
- and all its children nodes are either BST nodes themselves or null values. | ||
|
||
> The BST should support insertion, searching and removal of values. | ||
The removal method should only remove the first instance of the target value. | ||
|
||
|
||
|
||
```python | ||
class BST: | ||
""" | ||
We'll use the iterative approach (due to constant space). | ||
Recursive approach creates a call stack in memory -> O(n) space. | ||
""" | ||
|
||
def __init__(self, value): | ||
self.value = value | ||
self.left = None | ||
self.right = None | ||
|
||
def insert(self, value): | ||
"""Average Case: O(log(N)) time | O(1) space | ||
Worst Case: (Where the tree is unbalanced | ||
and has only one branch to the left) | ||
O(n) time, where n = number of nodes in the tree | ||
O(1) space | ||
""" | ||
current_node = self | ||
while True: | ||
if value < current_node.value: | ||
if current_node.left is None: | ||
current_node.left = BST(value) | ||
break | ||
else: | ||
current_node = current_node.left | ||
else: | ||
# value is greater than current node's value | ||
if current_node.right is None: | ||
current_node.right = BST(value) | ||
break | ||
else: | ||
current_node = current_node.right | ||
return self | ||
|
||
def contains(self, value): | ||
"""Average Case: O(log(N)) time | O(1) space | ||
Worst Case: O(n) time | O(1) space | ||
""" | ||
current_node = self | ||
while current_node is not None: | ||
if value < current_node.value: | ||
current_node = current_node.left | ||
elif value > current_node.value: | ||
current_node = current_node.right | ||
else: | ||
# found it! | ||
return True | ||
return False | ||
|
||
def remove(self, value, parent_node=None): | ||
"""Average Case: O(log(N)) time | O(1) space | ||
Worst Case: O(n) time, O(1) space | ||
""" | ||
current_node = self | ||
while current_node is not None: | ||
if value < current_node.value: | ||
parent_node = current_node | ||
current_node = current_node.left | ||
elif value > current_node.value: | ||
parent_node = current_node | ||
current_node = current_node.right | ||
else: | ||
# we've found the node, time to delete it | ||
if current_node.left is not None and current_node.right is not None: | ||
# set current node value = smallest value of right subtree. | ||
current_node.value = current_node.right.get_min_value() | ||
current_node.right.remove(current_node.value, current_node) | ||
elif parent_node is None: | ||
# if we are removing the root node (it does not have a parent node) | ||
if current_node.left is not None: | ||
current_node.value = current_node.left.value | ||
current_node.right = current_node.left.right | ||
current_node.left = current_node.left.left | ||
elif current_node.right is not None: | ||
current_node.value = current_node.right.value | ||
current_node.left = current_node.right.left | ||
current_node.right = current_node.right.right | ||
else: | ||
# no child nodes exist for this BST, so do nothing | ||
pass | ||
elif parent_node.left == current_node: | ||
parent_node.left = ( | ||
current_node.left if current_node.left is not None else | ||
current_node.right) | ||
elif parent_node.right == current_node: | ||
parent_node.right = ( | ||
current_node.left if current_node.left is not None else | ||
current_node.right) | ||
break | ||
return self | ||
|
||
def get_min_value(self): | ||
"""Finds the smallest value in a sub-tree.""" | ||
current_node = self | ||
while current_node.left is not None: | ||
current_node = current_node.left | ||
return current_node.value | ||
``` | ||
|
||
|
||
```python | ||
bst = BST(10).insert(5).insert(15).insert( | ||
7).insert(2).insert(14).insert(22) | ||
|
||
bst.contains(22) | ||
``` | ||
|
||
|
||
|
||
|
||
True | ||
|
||
|
||
|
||
|
||
```python | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
```python | ||
""" | ||
Given a binary tree, traverse it, adding the node values into an array, | ||
returning the array. | ||
Assume a BST is defined as follows: | ||
* The left subtree of a node contains only nodes with keys < the node's key. | ||
* The right subtree of a node contains only nodes with keys > the node's key. | ||
* Both the left and right subtrees must also be binary search trees. | ||
""" | ||
|
||
|
||
def in_order_traverse(tree, array): | ||
""" | ||
Complexity: O(n) time, O(n) space | ||
NOTE: If we were not storing any array, the space complexity = O(d) | ||
where d=depth of the longest branch in the BST. | ||
""" | ||
if tree is not None: | ||
in_order_traverse(tree.left, array) | ||
array.append(tree.value) | ||
in_order_traverse(tree.right, array) | ||
return array | ||
|
||
|
||
def pre_order_traverse(tree, array): | ||
""" | ||
Complexity: O(n) time, O(n) space. | ||
""" | ||
if tree is not None: | ||
array.append(tree.value) | ||
pre_order_traverse(tree.left, array) | ||
pre_order_traverse(tree.right, array) | ||
return array | ||
|
||
|
||
def post_order_traverse(tree, array): | ||
""" | ||
Complexity: O(n) time, O(n) space""" | ||
if tree is not None: | ||
post_order_traverse(tree.left, array) | ||
post_order_traverse(tree.right, array) | ||
array.append(tree.value) | ||
return array | ||
|
||
``` | ||
|
||
|
||
```python | ||
|
||
``` |
Oops, something went wrong.