forked from TheAlgorithms/Python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
is_bst.py
131 lines (103 loc) · 3.79 KB
/
is_bst.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
119
120
121
122
123
124
125
126
127
128
129
130
131
"""
Author : Alexander Pantyukhin
Date : November 2, 2022
Task:
Given the root of a binary tree, determine if it is a valid binary search
tree (BST).
A valid binary search tree is defined as follows:
- The left subtree of a node contains only nodes with keys less than the node's key.
- The right subtree of a node contains only nodes with keys greater than the node's key.
- Both the left and right subtrees must also be binary search trees.
Implementation notes:
Depth-first search approach.
leetcode: https://leetcode.com/problems/validate-binary-search-tree/
Let n is the number of nodes in tree
Runtime: O(n)
Space: O(1)
"""
from __future__ import annotations
from dataclasses import dataclass
@dataclass
class TreeNode:
data: float
left: TreeNode | None = None
right: TreeNode | None = None
def is_binary_search_tree(root: TreeNode | None) -> bool:
"""
>>> is_binary_search_tree(TreeNode(data=2,
... left=TreeNode(data=1),
... right=TreeNode(data=3))
... )
True
>>> is_binary_search_tree(TreeNode(data=0,
... left=TreeNode(data=-11),
... right=TreeNode(data=3))
... )
True
>>> is_binary_search_tree(TreeNode(data=5,
... left=TreeNode(data=1),
... right=TreeNode(data=4, left=TreeNode(data=3)))
... )
False
>>> is_binary_search_tree(TreeNode(data='a',
... left=TreeNode(data=1),
... right=TreeNode(data=4, left=TreeNode(data=3)))
... )
Traceback (most recent call last):
...
ValueError: Each node should be type of TreeNode and data should be float.
>>> is_binary_search_tree(TreeNode(data=2,
... left=TreeNode([]),
... right=TreeNode(data=4, left=TreeNode(data=3)))
... )
Traceback (most recent call last):
...
ValueError: Each node should be type of TreeNode and data should be float.
"""
# Validation
def is_valid_tree(node: TreeNode | None) -> bool:
"""
>>> is_valid_tree(None)
True
>>> is_valid_tree('abc')
False
>>> is_valid_tree(TreeNode(data='not a float'))
False
>>> is_valid_tree(TreeNode(data=1, left=TreeNode('123')))
False
"""
if node is None:
return True
if not isinstance(node, TreeNode):
return False
try:
float(node.data)
except (TypeError, ValueError):
return False
return is_valid_tree(node.left) and is_valid_tree(node.right)
if not is_valid_tree(root):
raise ValueError(
"Each node should be type of TreeNode and data should be float."
)
def is_binary_search_tree_recursive_check(
node: TreeNode | None, left_bound: float, right_bound: float
) -> bool:
"""
>>> is_binary_search_tree_recursive_check(None)
True
>>> is_binary_search_tree_recursive_check(TreeNode(data=1), 10, 20)
False
"""
if node is None:
return True
return (
left_bound < node.data < right_bound
and is_binary_search_tree_recursive_check(node.left, left_bound, node.data)
and is_binary_search_tree_recursive_check(
node.right, node.data, right_bound
)
)
return is_binary_search_tree_recursive_check(root, -float("inf"), float("inf"))
if __name__ == "__main__":
import doctest
doctest.testmod()