From 0dd29c326eff4b8fbf8b1ad18ee68238e4268f75 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 17 Oct 2023 02:49:35 +0200 Subject: [PATCH 1/6] Simplify is_bst.py --- data_structures/binary_tree/is_bst.py | 162 ++++++++++---------------- 1 file changed, 63 insertions(+), 99 deletions(-) diff --git a/data_structures/binary_tree/is_bst.py b/data_structures/binary_tree/is_bst.py index 0b2ef8c9ffde..30305b0af8c2 100644 --- a/data_structures/binary_tree/is_bst.py +++ b/data_structures/binary_tree/is_bst.py @@ -1,131 +1,95 @@ """ -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). +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 +If n is the number of nodes in the tree then: Runtime: O(n) Space: O(1) """ - from __future__ import annotations +from collections.abc import Iterator from dataclasses import dataclass @dataclass -class TreeNode: +class Node: 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 + left: Node | None = None + right: Node | None = None - >>> 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: + def __iter__(self) -> Iterator[float]: """ - >>> 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 + >>> root = Node(data=2.1) + >>> list(root) + [2.1] + >>> root.left=Node(data=2.0) + >>> list(root) + [2.0, 2.1] + >>> root.right=Node(data=2.2) + >>> list(root) + [2.0, 2.1, 2.2] """ - 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: + if self.left: + yield from self.left + yield self.data + if self.right: + yield from self.right + + @property + def is_sorted(self) -> bool: """ - >>> is_binary_search_tree_recursive_check(None) + >>> Node(data='abc').is_sorted + True + >>> Node(data=2, + ... left=Node(data=1.999), + ... right=Node(data=3)).is_sorted True - >>> is_binary_search_tree_recursive_check(TreeNode(data=1), 10, 20) + >>> Node(data=0, + ... left=Node(data=0), + ... right=Node(data=0)).is_sorted + True + >>> Node(data=0, + ... left=Node(data=-11), + ... right=Node(data=3)).is_sorted + True + >>> Node(data=5, + ... left=Node(data=1), + ... right=Node(data=4, left=Node(data=3))).is_sorted False + >>> Node(data='a', + ... left=Node(data=1), + ... right=Node(data=4, left=Node(data=3))).is_sorted + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'str' and 'int' + >>> Node(data=2, + ... left=Node([]), + ... right=Node(data=4, left=Node(data=3))).is_sorted + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'int' and 'list' """ - - 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 self.left and (self.data < self.left.data or not self.left.is_sorted): + return False + if self.right and (self.data > self.right.data or not self.right.is_sorted): + return False + return True if __name__ == "__main__": import doctest doctest.testmod() + tree = Node(data=2.1, left=Node(data=2.0), right=Node(data=2.2)) + print(f"Tree {list(tree)} is sorted: {tree.is_sorted = }.") + tree.right.data = 2.0 + print(f"Tree {list(tree)} is sorted: {tree.is_sorted = }.") + tree.right.data = 2.1 + print(f"Tree {list(tree)} is sorted: {tree.is_sorted = }.") From d47de46d345d5ce049ae0100a07ee3941c612c47 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Tue, 17 Oct 2023 00:49:48 +0000 Subject: [PATCH 2/6] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index d878f1c79a2d..9098cd100cdd 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -200,6 +200,7 @@ * [Floor And Ceiling](data_structures/binary_tree/floor_and_ceiling.py) * [Inorder Tree Traversal 2022](data_structures/binary_tree/inorder_tree_traversal_2022.py) * [Is Bst](data_structures/binary_tree/is_bst.py) + * [Is Sum Tree](data_structures/binary_tree/is_sum_tree.py) * [Lazy Segment Tree](data_structures/binary_tree/lazy_segment_tree.py) * [Lowest Common Ancestor](data_structures/binary_tree/lowest_common_ancestor.py) * [Maximum Fenwick Tree](data_structures/binary_tree/maximum_fenwick_tree.py) From ded2c3b5df5d13c6757ae3dd1020d2b75fdac55e Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 17 Oct 2023 02:55:13 +0200 Subject: [PATCH 3/6] Update is_bst.py --- data_structures/binary_tree/is_bst.py | 1 + 1 file changed, 1 insertion(+) diff --git a/data_structures/binary_tree/is_bst.py b/data_structures/binary_tree/is_bst.py index 30305b0af8c2..16b9784d0cb7 100644 --- a/data_structures/binary_tree/is_bst.py +++ b/data_structures/binary_tree/is_bst.py @@ -89,6 +89,7 @@ def is_sorted(self) -> bool: doctest.testmod() tree = Node(data=2.1, left=Node(data=2.0), right=Node(data=2.2)) print(f"Tree {list(tree)} is sorted: {tree.is_sorted = }.") + assert tree.right tree.right.data = 2.0 print(f"Tree {list(tree)} is sorted: {tree.is_sorted = }.") tree.right.data = 2.1 From 595c7a691f8f88f3400c589a0a7702d08a08dc5c Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 19 Oct 2023 17:57:03 +0200 Subject: [PATCH 4/6] Rename is_bst.py to is_sorted.py --- data_structures/binary_tree/{is_bst.py => is_sorted.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data_structures/binary_tree/{is_bst.py => is_sorted.py} (100%) diff --git a/data_structures/binary_tree/is_bst.py b/data_structures/binary_tree/is_sorted.py similarity index 100% rename from data_structures/binary_tree/is_bst.py rename to data_structures/binary_tree/is_sorted.py From c6d76b69a9f660276a780e3946eea627beaf50d4 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 19 Oct 2023 15:57:20 +0000 Subject: [PATCH 5/6] updating DIRECTORY.md --- DIRECTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 9098cd100cdd..0999d2e8687a 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -199,7 +199,7 @@ * [Flatten Binarytree To Linkedlist](data_structures/binary_tree/flatten_binarytree_to_linkedlist.py) * [Floor And Ceiling](data_structures/binary_tree/floor_and_ceiling.py) * [Inorder Tree Traversal 2022](data_structures/binary_tree/inorder_tree_traversal_2022.py) - * [Is Bst](data_structures/binary_tree/is_bst.py) + * [Is Sorted](data_structures/binary_tree/is_sorted.py) * [Is Sum Tree](data_structures/binary_tree/is_sum_tree.py) * [Lazy Segment Tree](data_structures/binary_tree/lazy_segment_tree.py) * [Lowest Common Ancestor](data_structures/binary_tree/lowest_common_ancestor.py) From 40f86fe6ce2eccae5d7fdfd367075a9bd7308daf Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 19 Oct 2023 18:56:13 +0200 Subject: [PATCH 6/6] Update data_structures/binary_tree/is_sorted.py Co-authored-by: Tianyi Zheng --- data_structures/binary_tree/is_sorted.py | 1 + 1 file changed, 1 insertion(+) diff --git a/data_structures/binary_tree/is_sorted.py b/data_structures/binary_tree/is_sorted.py index 16b9784d0cb7..5876c5a9c96a 100644 --- a/data_structures/binary_tree/is_sorted.py +++ b/data_structures/binary_tree/is_sorted.py @@ -6,6 +6,7 @@ - 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. +In effect, a binary tree is a valid BST if its nodes are sorted in ascending order. leetcode: https://leetcode.com/problems/validate-binary-search-tree/ If n is the number of nodes in the tree then: