def generate_tree_helper(i: int, arr: List[BinaryTree], nodes: int) -> BinaryTree: tree = arr[i] stack = Stack() stack.push(tree.root) while not stack.is_empty(): # generating the new tree with 1 new node node = stack.pop() if not node.left: node.left = Node(0) for j in range(nodes): if j != i and tree == arr[j]: node.left = None break else: return tree else: stack.push(node.left) if not node.right: node.right = Node(0) for j in range(nodes): if j != i and tree == arr[j]: node.right = None break else: return tree else: stack.push(node.right)
def __init__( self, val: Union[int, float, str, Callable], left: Optional[ExpressionTreeNode] = None, right: Optional[ExpressionTreeNode] = None, ) -> None: Node.__init__(self, val, left, right)
def merge_trees_helper(node: Node, node1: Node, node2: Node) -> None: n1_l_val, n1_r_val = 0, 0 n2_l_val, n2_r_val = 0, 0 n1_l, n1_r = None, None n2_l, n2_r = None, None # tree1 node related data generation if node1: if node1.left: n1_l_val = node1.left.val n1_l = node1.left if node1.right: n1_r_val = node1.right.val n1_r = node1.right # tree2 node related data generation if node2: if node2.left: n2_l_val = node2.left.val n2_l = node2.left if node2.right: n2_r_val = node2.right.val n2_r = node2.right # left node generation if n1_l is not None or n2_l is not None: node.left = Node(n1_l_val + n2_l_val) merge_trees_helper(node.left, n1_l, n2_l) # right node generation if n1_r is not None or n2_r is not None: node.right = Node(n1_r_val + n2_r_val) merge_trees_helper(node.right, n1_r, n2_r)
def prune_helper(node: Node) -> None: if node.left: prune_helper(node.left) if node.left.val == 0: if not node.left.left and not node.left.right: temp = node.left node.left = None del temp if node.right: prune_helper(node.right) if node.right.val == 0: if not node.right.left and not node.right.right: temp = node.right node.right = None del temp
def generate() -> BinaryTree: tree = BinaryTree() tree.root = Node(randint(1, 1000)) generate_helper(tree.root, 0.7, 0.7) # suggestion: don't use higher values for probability, it will lead to recursion # error return tree
def generate_cartesian_tree_helper(arr: List[int], last: Optional[Node] = None, root: Optional[Node] = None) -> Node: if not arr: return root # Cartesian tree generation node = Node(arr[0]) if not last: # root of the tree return generate_cartesian_tree_helper(arr[1:], node, node) if last.val > node.val: # property of Cartesian tree node.left = last return generate_cartesian_tree_helper(arr[1:], node, node) last.right = node return generate_cartesian_tree_helper(arr[1:], last, last)
def invert_helper(node: Node) -> None: node.right, node.left = node.left, node.right # recursively inverting the children if node.right is not None: invert_helper(node.right) if node.left is not None: invert_helper(node.left)
def generate_helper( node: Node, probability_add_children: float = 0.5, probability_add_branch: float = 0.5, ) -> None: if random() > probability_add_children: return # generating the left branch if random() < probability_add_branch: node.left = Node(randint(1, 1000)) generate_helper(node.left, probability_add_children, probability_add_branch) # generating the right branch if random() < probability_add_branch: node.right = Node(randint(1, 1000)) generate_helper(node.right, probability_add_children, probability_add_branch)
def create_trees(n: int) -> List[BinaryTree]: tree_arr = [] if n == 0: return tree_arr tree = BinaryTree() tree.root = Node(0) tree_arr.append(tree) create_trees_helper(tree_arr, n - 1) return tree_arr
def deserialize(string: str) -> BinaryTree: # the string needs to have the same format as the binary tree serialization # eg: data is padded with single quotes (') and comma (,) is used as a delimiter data = string.split(",") queue = Queue() for node in data: queue.enqueue(node) tree = BinaryTree() tree.root = Node(queue.dequeue().strip("'")) deserialize_helper(tree.root, queue) return tree
def get_huffman_code(char_freq: Dict[str, int]) -> Dict[str, str]: # calculating Huffman code nodes = sorted(char_freq.items(), key=lambda x: x[1], reverse=True) while len(nodes) > 1: key1, c1 = nodes[-1] key2, c2 = nodes[-2] nodes = nodes[:-2] node = Node(None, key1, key2) nodes.append((node, c1 + c2)) nodes = sorted(nodes, key=lambda x: x[1], reverse=True) huffmanCode = huffman_code_tree(nodes[0][0]) return huffmanCode
def merge_trees(tree1: BinaryTree, tree2: BinaryTree) -> BinaryTree: tree = BinaryTree() if not tree1.root and not tree2.root: return tree # root generation r1, r2 = 0, 0 if tree1.root: r1 = tree1.root.val if tree2.root: r2 = tree2.root.val tree.root = Node(r1 + r2) # generating rest of the tree merge_trees_helper(tree.root, tree1.root, tree2.root) return tree
def deserialize_helper(node: Node, queue: Queue) -> Node: # helper function to deserialize a string into a Binary Tree # data is a queue containing the data as a prefix notation can be easily decoded # using a queue left = queue.dequeue().strip("'") if left != "None": # if the left child exists, its added to the tree node.left = Node(left) node.left = deserialize_helper(node.left, queue) right = queue.dequeue().strip("'") if right != "None": # if the right child exists, its added to the tree node.right = Node(right) node.right = deserialize_helper(node.right, queue) return node
def generate_tree(preorder: List[int], inorder: List[int]) -> BinaryTree: length = len(preorder) if length != len(inorder): raise RuntimeError if length == 0: return BinaryTree() # generating the root root = preorder[0] tree = BinaryTree() tree.root = Node(root) # generating the rest of the tree if length > 1: i = inorder.index(root) # partitioning the nodes as per the branch inorder_left, preorder_left = (inorder[:i], preorder[1 : i + 1]) inorder_right, preorder_right = (inorder[i + 1 :], preorder[i + 1 :]) # creating a tree for each branch tree_left = generate_tree(preorder_left, inorder_left) tree_right = generate_tree(preorder_right, inorder_right) # attaching the sub-tree to their respective branch tree.root.left = tree_left.root tree.root.right = tree_right.root return tree
def create_full_bin_tree_helper(node: Node) -> None: # if a node with one missing child is encountered, the value is replaced by its # child and the children of the current node overwritten with the child's children if node.right is None and node.left is None: return elif node.left is not None and node.right is None: node.val = node.left.val node.right = node.left.right node.left = node.left.left create_full_bin_tree_helper(node) elif node.left is None and node.right is not None: node.val = node.right.val node.left = node.right.left node.right = node.right.right create_full_bin_tree_helper(node) elif node.left is not None and node.right is not None: create_full_bin_tree_helper(node.left) create_full_bin_tree_helper(node.right)
if node.parent: return node.parent.val return None def inorder_successor(node: Node) -> Optional[int]: if not node: return return inorder_successor_helper(node) # adding the parent pointer to Node class setattr(Node, "parent", None) if __name__ == "__main__": a = Node(10) b = Node(5) c = Node(30) d = Node(22) e = Node(35) a.left = b a.right = c c.left = d c.right = e b.parent = a c.parent = a d.parent = c e.parent = c
get_bottom_view_helper(node.left, depth + 1, hd - 1, accumulator) if node.right: get_bottom_view_helper(node.right, depth + 1, hd + 1, accumulator) return accumulator def get_bottom_view(tree: BinaryTree) -> List[int]: data = get_bottom_view_helper(tree.root, 0, 0, {}) res_arr = [(hd, data[hd][1]) for hd in data] res_arr.sort(key=lambda elem: elem[0]) return [elem for _, elem in res_arr] if __name__ == "__main__": tree = BinaryTree() tree.root = Node(5) tree.root.left = Node(3) tree.root.right = Node(7) tree.root.left.left = Node(1) tree.root.left.right = Node(4) tree.root.right.left = Node(6) tree.root.right.right = Node(9) tree.root.left.left.left = Node(0) tree.root.right.right.left = Node(8) print(tree)
((left_sum + node.val), left + [node.val]), ((right_sum + node.val), right + [node.val]), key=lambda x: x[0], ) def minimum_path_sum(tree: BinaryTree) -> List[int]: if not tree.root: raise ValueError("Empty Tree") _, path = minimum_path_sum_helper(tree.root) return path[::-1] if __name__ == "__main__": tree = BinaryTree() tree.root = Node(10) tree.root.left = Node(5) tree.root.right = Node(5) tree.root.left.right = Node(2) tree.root.right.right = Node(1) tree.root.right.right.left = Node(-1) print(tree) print(minimum_path_sum(tree)) """ SPECS:
if sub_tree1.left and find_helper(sub_tree1.left, sub_tree2): return True if sub_tree1.right and find_helper(sub_tree1.right, sub_tree2): return True return False def get_match(s: BinaryTree, t: BinaryTree) -> bool: if s.root and t.root: return find_helper(s.root, t.root) return False if __name__ == "__main__": tree1 = BinaryTree() tree1.root = Node(0) tree1.root.left = Node(1) tree1.root.right = Node(2) tree1.root.right.left = Node(3) tree1.root.right.right = Node(4) tree2 = BinaryTree() tree2.root = Node(2) tree2.root.left = Node(3) tree2.root.right = Node(4) tree3 = BinaryTree() tree3.root = Node(2) tree3.root.left = Node(3) tree3.root.right = Node(5)
right_height, right_node = 0, None if node.right: right_height, right_node = deepest_node_helper(node.right) # comparing and returning the deepest node if left_height > right_height: return left_height + 1, left_node return right_height + 1, right_node def deepest_node(tree: BinaryTree) -> Node: _, node = deepest_node_helper(tree.root) return node if __name__ == "__main__": tree = BinaryTree() tree.root = Node("a") tree.root.left = Node("b") tree.root.right = Node("c") tree.root.left.left = Node("d") print(deepest_node(tree)) """ SPECS: TIME COMPLEXITY: O(n) SPACE COMPLEXITY: O(log(n)) [recursion depth] """
# the string needs to have the same format as the binary tree serialization # eg: data is padded with single quotes (') and comma (,) is used as a delimiter data = string.split(",") queue = Queue() for node in data: queue.enqueue(node) tree = BinaryTree() tree.root = Node(queue.dequeue().strip("'")) deserialize_helper(tree.root, queue) return tree if __name__ == "__main__": tree = BinaryTree() tree.root = Node("root") tree.root.left = Node("left") tree.root.right = Node("right") tree.root.left.left = Node("left.left") print(serialize(tree)) generated_tree = deserialize( "'root','left','left.left','None','None','None','right','None','None'" ) print(serialize(generated_tree))
k: int) -> Tuple[Optional[int], Optional[int]]: generator = get_inorder_traverse_generator(tree) if not generator: return None, None # checking for the target sum previous = set() for val in generator: if (k - val) in previous: return (k - val), val previous.add(val) return None, None if __name__ == "__main__": tree = BinaryTree() tree.root = Node(10) tree.root.left = Node(5) tree.root.right = Node(15) tree.root.right.left = Node(11) tree.root.right.right = Node(15) print(get_target_sum(tree, 15)) print(get_target_sum(tree, 20)) print(get_target_sum(tree, 21)) print(get_target_sum(tree, 25)) print(get_target_sum(tree, 30)) print(get_target_sum(tree, 35)) """ SPECS:
tree1 = BinarySearchTree() tree1.add(5) tree1.add(9) tree1.add(1) tree1.add(4) tree1.add(10) tree1.add(3) tree1.add(2) tree1.add(10) tree1.add(7) print(is_binary_search_tree(tree1)) tree2 = BinaryTree() tree2.root = Node(5) tree2.root.left = Node(4) tree2.root.right = Node(6) print(is_binary_search_tree(tree2)) tree3 = BinaryTree() tree3.root = Node(5) tree3.root.left = Node(6) tree3.root.right = Node(4) print(is_binary_search_tree(tree3)) """ SPECS:
node.left = node.right.left node.right = node.right.right create_full_bin_tree_helper(node) elif node.left is not None and node.right is not None: create_full_bin_tree_helper(node.left) create_full_bin_tree_helper(node.right) def create_full_bin_tree(tree: BinaryTree) -> None: if tree.root: create_full_bin_tree_helper(tree.root) if __name__ == "__main__": tree = BinaryTree() tree.root = Node("a") tree.root.left = Node("b") tree.root.right = Node("c") tree.root.left.left = Node("d") tree.root.left.left.right = Node("f") tree.root.right.right = Node("e") tree.root.right.right.left = Node("g") tree.root.right.right.right = Node("h") print(tree) create_full_bin_tree(tree)
if node.right.val == 0: if not node.right.left and not node.right.right: temp = node.right node.right = None del temp def prune(tree: BinaryTree) -> BinaryTree: if tree.root: prune_helper(tree.root) return tree if __name__ == "__main__": tree = BinaryTree() tree.root = Node(0) tree.root.left = Node(1) tree.root.right = Node(0) tree.root.right.left = Node(1) tree.root.right.right = Node(0) tree.root.right.left.left = Node(0) tree.root.right.left.right = Node(0) print(tree) print(prune(tree)) """ SPECS:
if node is not None: if node.left: queue.enqueue(node.left) if node.right: queue.enqueue(node.right) curr_level_sum += node.val else: min_level_sum = min(curr_level_sum, min_level_sum) if len(queue) > 0: queue.enqueue(None) curr_level_sum = 0 return min_level_sum if __name__ == "__main__": a = Node(100) b = Node(200) c = Node(300) d = Node(400) e = Node(500) f = Node(600) g = Node(700) h = Node(800) a.left = b a.right = c b.left = d b.right = e c.left = f
return tree # root generation r1, r2 = 0, 0 if tree1.root: r1 = tree1.root.val if tree2.root: r2 = tree2.root.val tree.root = Node(r1 + r2) # generating rest of the tree merge_trees_helper(tree.root, tree1.root, tree2.root) return tree if __name__ == "__main__": tree1 = BinaryTree() tree1.root = Node(1) tree1.root.left = Node(2) tree1.root.right = Node(3) tree1.root.left.right = Node(4) print(tree1) tree2 = BinaryTree() tree2.root = Node(2) tree2.root.right = Node(-3) tree2.root.right.right = Node(10) print(tree2) print(merge_trees(tree1, tree2)) """ SPECS:
def __init__(self, val: int) -> None: Node.__init__(self, val) self.locked = False self.parent = None
current_balance = -1 <= (right_height - left_height) <= 1 height = max(left_height, right_height) + 1 return height, balance and current_balance def check_balance(tree: BinaryTree) -> bool: if tree.root is None: return True _, balance = height_helper(tree.root) return balance if __name__ == "__main__": tree = BinaryTree() tree.root = Node(0) tree.root.left = Node(1) tree.root.right = Node(2) tree.root.left.left = Node(3) tree.root.left.right = Node(4) print(check_balance(tree)) tree.root.left.right.left = Node(5) print(check_balance(tree)) """ SPECS:
if node.left and node.val > l_max_val: return l_height + 1, node, True, node.val, l_min_val elif node.right and node.val < r_min_val: return r_height + 1, node, True, r_max_val, node.val if l_height > r_height: return l_height, l_root, False, l_max_val, l_min_val return r_height, r_root, False, r_max_val, r_min_val def get_largest_bst_size(tree: BinaryTree) -> Tuple[int, int]: size, node, _, _, _ = get_largest_bst_size_helper(tree.root) return size, node.val if __name__ == "__main__": a = Node(3) b = Node(2) c = Node(6) d = Node(1) e = Node(1) f = Node(4) a.left = b a.right = c b.left = d b.right = e c.left = f tree = BinaryTree() tree.root = a