def construct_bst_helper(left_bound: int, right_bound: int) -> Optional[TreeNode]: if left_bound > right_bound: return None mid_point = (left_bound + right_bound) // 2 root_node = TreeNode(values[mid_point]) root_node.left = construct_bst_helper(left_bound, mid_point - 1) root_node.right = construct_bst_helper(mid_point + 1, right_bound) return root_node
def reversed_pre_order_traversal(current_node: TreeNode) -> None: """ :param current_node: flattening sub tree beneath current_node; current_node is not None """ nonlocal previous_node if current_node.right: reversed_pre_order_traversal(current_node.right) if current_node.left: reversed_pre_order_traversal(current_node.left) current_node.right = previous_node current_node.left = None previous_node = current_node
def _trim_boundary_helper(current_node: TreeNode) -> TreeNode: if not current_node: return current_node if current_node.val < low_val: # root and its left tree will be dropped return _trim_boundary_helper(current_node.right) elif current_node.val > high_val: # root and its right tree will be dropped return _trim_boundary_helper(current_node.left) current_node.left = _trim_boundary_helper(current_node.left) current_node.right = _trim_boundary_helper(current_node.right) return current_node
def mark_parent(current_node: TreeNode, parent_node: TreeNode = None) -> None: current_node.parent = parent_node if current_node.left: mark_parent(current_node.left, current_node) if current_node.right: mark_parent(current_node.right, current_node)
def convert_bst_helper(current_node: TreeNode) -> None: nonlocal accumulator if current_node is not None: convert_bst_helper(current_node.right) accumulator += current_node.val current_node.val = accumulator convert_bst_helper(current_node.left)
def build_bst(i: int, j: int) -> TreeNode: """ :return: build binary search tree for in_order_list[i: j] """ mid = (i + j) // 2 return TreeNode(in_order_list[mid], left=(build_bst(i, mid) if mid > i else None), right=(build_bst(mid + 1, j) if mid + 1 < j else None))
def construct_bst_helper( list_start: Optional[ListNode]) -> Optional[TreeNode]: if list_start is None: return None slow_ptr = list_start slow_before = None fast_ptr = list_start while fast_ptr.next and fast_ptr.next.next: slow_before = slow_ptr slow_ptr = slow_ptr.next fast_ptr = fast_ptr.next.next root_node = TreeNode(slow_ptr.val) if slow_before: slow_before.next = None root_node.left = construct_bst_helper(list_start) if slow_ptr.next: root_node.right = construct_bst_helper(slow_ptr.next) return root_node
def add_merkle_hash_to(current_node: TreeNode) -> str: """ :param current_node: add Merkle hash code to represent the sub tree beneath current_node :return: Merkle hash code of the sub tree beneath current_node """ current_node.hash_code = get_sh256_hash((add_merkle_hash_to(current_node.left) if current_node.left else '#') + str(current_node.val) + (add_merkle_hash_to(current_node.right) if current_node.right else '#')) return current_node.hash_code
def test_build_tree(node_list: List[Optional[int]]) -> BinaryTree: if not node_list or node_list[0] is None: return BinaryTree(None) return_tree = BinaryTree(TreeNode(node_list[0])) node_queue = deque([return_tree.root]) node_child_counter = 0 current_node = None for i in range(1, len(node_list)): if node_child_counter == 0: current_node = node_queue.popleft() if node_list[i] is not None: if node_child_counter: current_node.right = TreeNode(node_list[i]) node_queue.append(current_node.right) else: current_node.left = TreeNode(node_list[i]) node_queue.append(current_node.left) node_child_counter = (node_child_counter + 1) % 2 return return_tree
def invert_tree(root: TreeNode) -> Optional[TreeNode]: """ :param root: root of a binary tree :return: root of the inverted binary tree, after flipping left and right child of each node """ if root is None: return None right = invert_tree(root.right) if root.right else None left = invert_tree(root.left) if root.left else None root.left, root.right = right, left return root
def prune_tree_helper(current_root: TreeNode) -> bool: """ Prune the subtree of current_root :param current_root: root node of current sub tree; guaranteed not equals to None :return: whether subtree of current_root contains 1 """ subtree_contains_1 = False if current_root.left: if prune_tree_helper(current_root.left): subtree_contains_1 = True else: current_root.left = None if current_root.right: if prune_tree_helper(current_root.right): subtree_contains_1 = True else: current_root.right = None return current_root.val == 1 or subtree_contains_1
def trim_BST(root: TreeNode, low_val: int, high_val: int) -> TreeNode: """ Recursively remove all nodes whose values that are out of [low_val, high_val] :param root: root node of the original Binary Search Tree :param low_val: remove all nodes that are strictly less than low_val :param high_val: remove all nodes that are strictly greater than low_val :return: root of the updated Binary Search Tree """ if not root: return root if root.val < low_val: # root and its left tree will be dropped return trim_BST(root.right, low_val, high_val) elif root.val > high_val: # root and its right tree will be dropped return trim_BST(root.left, low_val, high_val) root.left = trim_BST(root.left, low_val, high_val) root.right = trim_BST(root.right, low_val, high_val) return root
def insert(self, v: TREE_NODE_TYPE) -> TREE_NODE_TYPE: """ :param v: insert a TreeNode into the tree with value node.val = v so that the tree remains complete :return: the value of the parent of the inserted TreeNode; """ parent_node = self.node_not_full[0] self.node_not_full.append(TreeNode(v)) if not parent_node.left: parent_node.left = self.node_not_full[-1] else: parent_node.right = self.node_not_full[-1] self.node_not_full.pop(0) return parent_node.val
def insert(self, value: TREE_NODE_TYPE) -> None: """ :return: insert a new node of value into the BST """ if self.root is None: self.root = TreeNode(value) else: current_node = self.root inserted = False while not inserted: if value < current_node.val: if not current_node.left: current_node.left = TreeNode(value) inserted = True else: current_node = current_node.left else: if not current_node.right: current_node.right = TreeNode(value) inserted = True else: current_node = current_node.right
def merge_trees(root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: """ :param root1: root of binary tree 1 :param root2: root of binary tree 2 :return: root of merged tree; returned tree may point to TreeNodes in root1 or root2 """ if root1 is None and root2 is None: return None if root1 is not None and root2 is not None: return TreeNode(root1.val + root2.val, left=merge_trees(root1.left, root2.left) if root1.left or root2.left else None, right=merge_trees(root1.right, root2.right) if root1.right or root2.right else None) else: return root1 if root1 else root2
def add_one_row(root: TreeNode, value: int, depth: int) -> TreeNode: """ :param root: root of a proper binary tree :param value: add a new row at level depth with all nodes set to value :param depth: add a new row at level depth with all nodes set to value :return: root of the new binary tree """ if depth == 1: return TreeNode(value, left=root) current_level = [root] current_depth = 1 while current_depth < depth - 1: next_level = [node.left for node in current_level if node.left is not None] next_level.extend([node.right for node in current_level if node.right is not None]) current_depth += 1 current_level = next_level for node in current_level: node.left = TreeNode(value, left=node.left) node.right = TreeNode(value, right=node.right) return root
def invert_tree(root: TreeNode) -> Optional[TreeNode]: """ :param root: root of a binary tree :return: root of the inverted binary tree, after flipping left and right child of each node """ if root is None: return None right = invert_tree(root.right) if root.right else None left = invert_tree(root.left) if root.left else None root.left, root.right = right, left return root node = TreeNode(4) node.left = TreeNode(2) node.left.left = TreeNode(1) node.left.right = TreeNode(3) node.right = TreeNode(7) node.right.left = TreeNode(6) node.right.right = TreeNode(9) tree = BinaryTree(node) assert tree.preorder_traversal() == [4, 2, 1, 3, 7, 6, 9] assert tree.inorder_traversal() == [1, 2, 3, 4, 6, 7, 9] assert tree.postorder_traversal() == [1, 3, 2, 6, 9, 7, 4] assert tree.layer_traversal_by_layer() == [[4], [2, 7], [1, 3, 6, 9]] assert tree.leetcode_traversal() == [ 4, 2, 7, 1, 3, 6, 9, None, None, None, None, None, None, None, None ]
# print('Deleted: %d, Remaining: %s' % (values[i], str(deletion_tree.traversal()))) assert deletion_tree.traversal() == values[:i] + values[i + 1:] expected_values = [6, 7, 8, 9, 10, 11, 12, 13] assert new_bst.traverse_range(6, 13) == expected_values assert new_bst.traverse_range(6, 14) == expected_values assert new_bst.traverse_range(5.5, 13) == expected_values sorted_list = list(range(1, 11)) head = LinkedList.create_linked_list(sorted_list) new_bst = BST(head) assert new_bst.traversal() == sorted_list assert new_bst.is_balanced() new_bst = BST([-1]) new_bst.root.right = TreeNode(1) new_bst.root.right.left = TreeNode(-1) assert new_bst.is_valid() new_bst = BST([1]) new_bst.root.left = TreeNode(-1) new_bst.root.left.right = TreeNode(1) assert not new_bst.is_valid() new_bst = BST([1, 3, 4]) new_bst.root.left.right = TreeNode(2) for i in range(1, 5): assert new_bst.kth_smallest_element( i) == i, "Expecting %d got %d" % (i, new_bst.kth_smallest_element(i)) assert new_bst.kth_smallest_element(5) is None