Exemplo n.º 1
0
def sorted_array_to_height_balanced_bst(array: List[int]) -> Optional[Node]:
    size = len(array)

    if size == 0:
        return None
    if size == 1:
        return Node(array[0])

    mid = size // 2

    root = Node(array[mid])
    root.left = sorted_array_to_height_balanced_bst(array[:mid])
    root.right = sorted_array_to_height_balanced_bst(array[mid + 1:])
    return root
Exemplo n.º 2
0
def _construct_bst(
    postorder: List[int], start_index: int, end_index: int
) -> Optional[Node]:
    if end_index < start_index:
        return None

    root = Node(postorder[end_index])

    left_last_index = find_index_of_smaller(postorder, start_index, end_index)
    root.left = _construct_bst(postorder, start_index, left_last_index)

    root.right = _construct_bst(
        postorder,
        left_last_index + 1,
        find_index_of_larger(postorder, left_last_index + 1, end_index),
    )
    return root
Exemplo n.º 3
0
def construct_bst(start: int, end: int) -> List[Optional[Node]]:
    if start > end:
        return [None]

    return_list = []

    for index in range(start, end + 1):
        left_subtrees = construct_bst(start, index - 1)
        right_subtrees = construct_bst(index + 1, end)

        for left in left_subtrees:
            for right in right_subtrees:
                root = Node(index)
                root.left = left
                root.right = right
                return_list.append(root)

    return return_list
Exemplo n.º 4
0
    def tree(start: int, end: int) -> Optional[Node]:
        nonlocal inorder_dict, l, index

        if start > end or start >= l:
            return None

        element: str = preorder[index]
        root: Node = Node(element)
        index += 1  # preorder traversal
        in_index: int = inorder_dict[element]

        if start < end:  # inorder traversal
            root.left = tree(start, in_index - 1)
            root.right = tree(in_index + 1, end)

        return root
Exemplo n.º 5
0
  a
 / \
 c  b
 \  / \
  f e  d
"""
from typing import Optional
from daily_problems.binary_tree_node import Node, inorder_traversal


def invert_tree(root_node: Optional[Node] = None) -> Optional[Node]:
    if root_node:
        root_node.left, root_node.right = root_node.right, root_node.left
        invert_tree(root_node.right)
        invert_tree(root_node.left)

    return root_node


if __name__ == "__main__":
    root = Node("a")
    root.left = Node("b")
    root.right = Node("c")
    root.left.left = Node("d")
    root.left.right = Node("e")
    root.right.left = Node("f")
    print("inorder traversal")
    inorder_traversal(root)
    print("inorder traversal of inverted tree")
    inorder_traversal(invert_tree(root))
Exemplo n.º 6
0
5    5
 \    \
  2    1
      / \
    -1   2
"""
from typing import Optional

from daily_problems.binary_tree_node import Node


def min_sum_path_root_to_leaf(root: Optional[Node]) -> int:
    if not root:
        return 0
    if root.left is None and root.right is None:
        return root.data
    return root.data + min(min_sum_path_root_to_leaf(root.left),
                           min_sum_path_root_to_leaf(root.right))


if __name__ == "__main__":
    tree = Node(10)
    tree.left = Node(5)
    tree.right = Node(5)
    tree.left.right = Node(2)
    tree.right.right = Node(1)
    tree.right.right.left = Node(-1)
    tree.right.right.right = Node(2)

    assert min_sum_path_root_to_leaf(tree) == 15
Exemplo n.º 7
0
        return 0, 0

    left_sum_tree, left_sum_node = 0, 0
    right_sum_tree, right_sum_node = 0, 0

    if root_node.left:
        left_sum_tree, left_sum_node = _max_sum_path(root_node.left)
    if root_node.right:
        right_sum_tree, right_sum_node = _max_sum_path(root_node.right)

    return (
        left_sum_node + right_sum_node + root_node.data,
        root_node.data + max(left_sum_tree, right_sum_tree),
    )


def max_sum_path(root_node: Optional[Node] = None) -> int:
    return max(*_max_sum_path(root_node))


if __name__ == "__main__":
    root = Node(10)
    root.left = Node(2)
    root.right = Node(10)
    root.left.left = Node(20)
    root.left.right = Node(1)
    root.right.right = Node(-25)
    root.right.right.left = Node(3)
    root.right.right.right = Node(4)
    assert max_sum_path(root) == 42
Exemplo n.º 8
0
"""
from typing import Optional

from daily_problems.binary_tree_node import Node
from gfg.trees.tree_traversal import inorder


def prune(node: Optional[Node]) -> Optional[Node]:
    if not node:
        return None

    node.left = prune(node.left)
    node.right = prune(node.right)

    if node.data == 1 or node.left or node.right:
        return node

    return None


if __name__ == "__main__":
    tree = Node(0)
    tree.left = Node(1)
    tree.right = Node(0)
    tree.right.left = Node(1)
    tree.right.left.left = Node(0)
    tree.right.left.right = Node(0)

    tree = prune(tree)
    inorder(tree)
Exemplo n.º 9
0
    if root_node.left is None and root_node.right is None:
        count[root_node.data] += 1
        return count, root_node.data

    count, left_sum = _subtree_sum(root_node.left, count)
    count, right_sum = _subtree_sum(root_node.right, count)
    total = left_sum + right_sum + root_node.data
    count[total] += 1
    return count, total


def subtree_sum(root_node: Node) -> int:
    count, _ = _subtree_sum(root_node, defaultdict(int))

    max_occ = 0
    return_val = 0

    for key, value in count.items():
        if value > max_occ:
            return_val = key
            max_occ = value

    return return_val


if __name__ == "__main__":
    root = Node(5)
    root.left = Node(2)
    root.right = Node(-5)
    assert subtree_sum(root) == 2
Exemplo n.º 10
0
    """
    time complexity: O(n)
    space complexity: O(n)  # stack
    """
    if root_node is None:
        return 0, True

    count_left, is_left_unival = count_unival(root_node.left)
    count_right, is_right_unival = count_unival(root_node.right)
    total_count = count_left + count_right

    if is_left_unival and is_right_unival:
        if (root_node.left and root_node.data != root_node.left.data) or (
            root_node.right and root_node.data != root_node.right.data
        ):
            return total_count, False
        return total_count + 1, True

    return total_count, False


if __name__ == "__main__":
    root = Node(0)
    root.left = Node(1)
    root.right = Node(0)
    root.right.left = Node(1)
    root.right.right = Node(0)
    root.right.left.left = Node(1)
    root.right.left.right = Node(1)
    print(count_unival(root)[0])
Exemplo n.º 11
0
    # insert node and level
    q.append((root_node, 0))

    while q:
        node, level = q.popleft()
        d[level] += node.data

        if node.left:
            q.append((node.left, level + 1))
        if node.right:
            q.append((node.right, level + 1))

    min_sum = sys.maxsize
    min_sum_level = 0

    for level, level_sum in d.items():
        if level_sum < min_sum:
            min_sum = level_sum
            min_sum_level = level

    return min_sum_level


if __name__ == "__main__":
    root = Node(10)
    root.left = Node(2)
    root.right = Node(3)
    root.left.left = Node(4)
    root.left.right = Node(5)
    assert level_with_min_sum(root) == 1
Exemplo n.º 12
0
                 position: int) -> Dict[int, int]:
    if not root_node:
        return view

    view[
        position] = root_node.data  # always override, bottommost view is more important
    view = _bottom_view(root_node.left, view, position - 1)
    view = _bottom_view(root_node.right, view, position + 1)
    return view


def bottom_view(root_node: Node) -> List[int]:
    view = _bottom_view(root_node, {}, 0)
    start_index = min(view.keys())
    end_index = max(view.keys())

    return [view[index] for index in range(start_index, end_index + 1)]


if __name__ == "__main__":
    root = Node(5)
    root.left = Node(3)
    root.left.left = Node(1)
    root.left.right = Node(4)
    root.left.left.left = Node(0)
    root.right = Node(7)
    root.right.left = Node(6)
    root.right.right = Node(9)
    root.right.right.left = Node(8)
    print(bottom_view(root))
Exemplo n.º 13
0
def arithmetic_bin_tree(root_node: Optional[Node]) -> Union[int, float]:
    """
    Assuming everything is good. There are no corner cases
    Using Inorder tree traversal for calculation
    Time Complexity: O(n)
    Space Complexity: O(n) # stack
    """
    if not root_node:
        return 0

    left_num: Union[int, float] = arithmetic_bin_tree(root_node.left)

    if left_num:
        symbol = sign_dict[root_node.data]
        right_num: Union[int, float] = arithmetic_bin_tree(root_node.right)
        return symbol(left_num, right_num)

    return int(root_node.data)


if __name__ == "__main__":
    root = Node("*")
    root.left = Node("+")
    root.right = Node("+")
    root.left.left = Node(3)
    root.left.right = Node(2)
    root.right.left = Node(4)
    root.right.right = Node(5)
    assert arithmetic_bin_tree(root) == 45
Exemplo n.º 14
0
        return root_node, True, size_left + size_right + 1

    if size_left >= size_right:
        return left_bst, False, size_left

    return right_bst, False, size_right


def largest_bst(
        root_node: Optional[Node] = None) -> Tuple[Optional[Node], int]:
    bst_node, is_bst, size = _largest_bst(-sys.maxsize, sys.maxsize, root_node)
    return bst_node, size


if __name__ == "__main__":
    root = Node(5)
    root.left = Node(2)
    root.right = Node(4)
    root.left.left = Node(1)
    root.left.right = Node(3)

    response = largest_bst(root)
    assert response[0].data == 2
    assert response[1] == 3

    root = Node(50)
    root.left = Node(30)
    root.right = Node(60)
    root.left.left = Node(5)
    root.left.right = Node(20)
    root.right.left = Node(45)
Exemplo n.º 15
0
from daily_problems.binary_tree_node import Node


def bin_tree_path(root_node: Optional[Node]) -> List[List[int]]:
    if not root_node:
        return [[]]

    if root_node.left is None and root_node.right is None:
        return [[root_node.data]]

    return_list = []

    if root_node.left:
        for path in bin_tree_path(root_node.left):
            return_list.append([root_node.data] + path)

    if root_node.right:
        for path in bin_tree_path(root_node.right):
            return_list.append([root_node.data] + path)

    return return_list


if __name__ == "__main__":
    tree = Node(1)
    tree.left = Node(2)
    tree.right = Node(3)
    tree.right.left = Node(4)
    tree.right.right = Node(5)
    print(bin_tree_path(tree))
Exemplo n.º 16
0

def height_balanced(node: Node) -> Tuple[bool, int]:
    if node is None:
        return True, 0
    if node.left is None and node.right is None:
        return True, 1

    is_balanced_left, height_left = height_balanced(node.left)

    if not is_balanced_left:
        return is_balanced_left, height_left

    is_balanced_right, height_right = height_balanced(node.right)

    if not is_balanced_right or abs(height_right - height_left) > 1:
        return False, max(height_right, height_left)

    return True, max(height_right, height_left) + 1


if __name__ == "__main__":
    root = Node(1)
    root.left = Node(2)
    root.right = Node(3)
    root.left.left = Node(4)
    root.left.right = Node(5)
    root.left.right.right = Node(7)
    root.right.left = Node(6)
    assert height_balanced(root)[0] is True
Exemplo n.º 17
0
        if not root:
            return ""

        return str(root.data) + preorder(root.left) + preorder(root.right)

    first_inorder = inorder(root_node_1)
    first_preorder = preorder(root_node_1)
    second_inorder = inorder(root_node_2)
    second_preorder = preorder(root_node_2)

    return first_inorder.find(second_inorder) > -1 and first_preorder.find(
        second_preorder) > -1


if __name__ == "__main__":
    first = Node(26)
    first.right = Node(3)
    first.right.right = Node(3)
    first.left = Node(10)
    first.left.left = Node(4)
    first.left.left.right = Node(30)
    first.left.right = Node(6)

    second = Node(10)
    second.right = Node(6)
    second.left = Node(4)
    second.left.right = Node(30)
    assert is_subtree_naive(first, second) is True
    assert is_subtree_fast(first, second) is True

    third = Node(10)