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)
Example #2
0
 def __init__(
     self,
     val: Union[int, float, str, Callable],
     left: Optional[ExpressionTreeNode] = None,
     right: Optional[ExpressionTreeNode] = None,
 ) -> None:
     Node.__init__(self, val, left, right)
Example #3
0
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)
Example #4
0
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
Example #6
0
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)
Example #7
0
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
Example #12
0
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
Example #15
0
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
Example #17
0
        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))

Example #22
0
                   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:
Example #24
0
        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)
Example #25
0
        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
Example #27
0
        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:
Example #30
0
            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