-
Notifications
You must be signed in to change notification settings - Fork 0
/
insert_into_a_binary_search_tree.py
118 lines (98 loc) · 3.99 KB
/
insert_into_a_binary_search_tree.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#!/usr/bin/env python3
# Insert Into A Binary Search Tree
#
# https://leetcode.com/problems/insert-into-a-binary-search-tree/
#
# You are given the root node of a binary search tree (BST) and a value to
# insert into the tree. Return the root node of the BST after the insertion. It
# is guaranteed that the new value does not exist in the original BST.
#
# Notice that there may exist multiple valid ways for the insertion, as long as
# the tree remains a BST after insertion. You can return any of them.
from typing import List, Optional
from binary_tree import TreeNode
def test():
"""
Run `pytest <this-file>`.
"""
def post_order_traversal(root: Optional[TreeNode]) -> List[int]:
order = []
def visit(node): order.append(node.val)
def traverse(node):
if node:
traverse(node.left)
traverse(node.right)
visit(node)
traverse(root)
return order
def test_algo(algo):
# 4
# 2 7
# 1 3
# into:
# 4
# 2 7
# 1 3 5
assert post_order_traversal(algo(root=TreeNode(4, TreeNode(2, TreeNode(1), TreeNode(3)), TreeNode(7)), val=5)) == [1, 3, 2, 5, 7, 4]
# Test all different algorithms/implementations
solution = Solution()
for algo in [solution.recursive, solution.iterative]:
test_algo(algo)
class Solution:
def recursive(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
"""
Approach: Recursive.
Idea: If the new value is smaller than current node's value, insert in left subtree, if larger insert in right subtree.
Time: O(log n): If the BST is balanced, we visit every level once, and height is log n.
Space: O(1): No additional memory is allocated.
Leetcode: 87 ms runtime, 18.69 MB memory
"""
def insert(node: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if node is None:
new_node = TreeNode(val)
return new_node
else:
if val == node.val:
raise Exception(f"node with value {val} already exists in BST")
elif val < node.val:
# Insert new node in left subtree.
node.left = insert(node.left, val)
else:
# Insert new node in right subtree.
node.right = insert(node.right, val)
return node
return insert(root, val)
def iterative(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
"""
Approach: Iterative.
Idea: If the new value is smaller than current node's value, insert in left subtree, if larger insert in right subtree.
Time: O(log n): If the BST is balanced, we visit every level once, and height is log n.
Space: O(1): No additional memory is allocated.
Leetcode: 86 ms runtime, 18.87 MB memory
"""
# TreeNode **cur = &root;
# while( *cur != NULL )
# cur = (val > (*cur)->val) ? &(*cur)->right : &(*cur)->left;
# *cur = new TreeNode(val);
# return root;
# Trying to mimic the power of C/C++ pointer magic, demonstrated above, in python:
if not root:
return TreeNode(val)
else:
curr = root
while curr:
if val == curr.val:
raise Exception(f"node with value {val} already exists in BST")
if val < curr.val:
# Traverse into left subtree.
if not curr.left:
curr.left = TreeNode(val)
break
curr = curr.left
else:
# Traverse into right subtree.
if not curr.right:
curr.right = TreeNode(val)
break
curr = curr.right
return root