Example #1
0
    def all_elements_in_two_binary_search_trees(self, root1: List[int],
                                                root2: List[int]) -> List[int]:
        root1 = TreeNode.deserialize(root1)
        root2 = TreeNode.deserialize(root2)

        def inorder(n):
            if n is None: return
            yield from inorder(n.left)
            yield n.val
            yield from inorder(n.right)

        def consume(g):
            try:
                return next(g)
            except StopIteration as e:
                return None

        def merge_values(root1, root2):
            g1, g2 = inorder(root1), inorder(root2)
            n1, n2 = consume(g1), consume(g2)
            while n1 is not None and n2 is not None:
                if n1 < n2:
                    yield n1
                    n1 = consume(g1)
                else:
                    yield n2
                    n2 = consume(g2)
            while n1 is not None:
                yield n1
                n1 = consume(g1)
            while n2 is not None:
                yield n2
                n2 = consume(g2)

        return list(merge_values(root1, root2))
    def inorder_successor_in_bst(self, root: List[int],
                                 p: List[int]) -> TreeNode:
        root = TreeNode.deserialize(root)
        p = TreeNode.deserialize(p)

        suc, t = None, root
        while t:
            if t.val <= p.val:
                t = t.right
            else:
                suc = t
                t = t.left
        return suc
Example #3
0
    def lowest_common_ancestor_of_a_binary_search_tree(self, root: List[int],
                                                       p: int,
                                                       q: int) -> TreeNode:
        root = TreeNode.deserialize(root)

        def find_node(node, num):
            if not node: return None
            if node.val == num: return node
            l = find_node(node.left, num)
            r = find_node(node.right, num)
            return l or r

        p = find_node(root, p)
        q = find_node(root, q)

        # Actual code starts from here
        def find_lca(root):
            if root in (None, p, q): return root
            l = find_lca(root.left)
            r = find_lca(root.right)
            if l and r: return root
            return l or r

        n = find_lca(root)
        return n.val
Example #4
0
    def recover_binary_search_tree(self, root: List[int]) -> TreeNode:
        root = TreeNode.deserialize(root)
        """
        Record first, second everytime first >= second
        """
        first = second = prev = None

        def inorder(n):
            nonlocal first, second, prev
            if n is None: return
            inorder(n.left)

            # 'prev is None' means root node can be included to first
            if not first and (prev is None or prev.val >= n.val):
                first = prev

            if first and prev and prev.val >= n.val:
                second = n

            prev = n
            inorder(n.right)

        inorder(root)

        first.val, second.val = second.val, first.val

        return root
    def binary_tree_level_order_traversal(self, root: typing.List[int]) -> TreeNode:
        root = TreeNode.deserialize(root)
        if root is None: return None
        sent = prev = TreeNode(0)

        def inorder(node):
            nonlocal prev
            if node is None: return
            inorder(node.left)
            # process node
            prev.right = node
            node.left = prev
            prev = node
            inorder(node.right)

        inorder(root)
        head = sent.right
        head.left = prev
        prev.right = head
        return head


        # 1. Perform inorder traversal and create the doubly linked list on the fly
        # 2. To access prev node after dfs, set prev as nonlocal variable
        """
    def inorder_successor_in_bst(self, root: List[int],
                                 p: List[int]) -> TreeNode:
        root = TreeNode.deserialize(root)
        p = TreeNode.deserialize(p)

        prev, successor = None, None

        def inorder(n):
            nonlocal prev, successor
            if n is None: return
            inorder(n.left)
            if prev is not None and prev.val == p.val:
                successor = n
            prev = n
            inorder(n.right)

        inorder(root)
        return successor
    def inorder_successor_in_bst(self, root: List[int],
                                 p: List[int]) -> TreeNode:
        root = TreeNode.deserialize(root)
        p = TreeNode.deserialize(p)

        prev, s, t = None, [], root
        while s or t:
            while t:
                s.append(t)
                t = t.left

            t = s.pop()
            if prev and prev.val == p.val:
                return t

            prev = t
            t = t.right
        return None
Example #8
0
    def binary_tree_postorder_traversal(self, root: List[int]) -> TreeNode:
        root = TreeNode.deserialize(root)

        def postorder(n):
            if n is None: return
            yield from postorder(n.left)
            yield from postorder(n.right)
            yield n.val

        return list(postorder(root))
Example #9
0
    def binary_tree_inorder_traversal(
            self, root: typing.List[int]) -> typing.List[int]:
        root = TreeNode.deserialize(root)

        def inorder(n):
            if n is None: return
            yield from inorder(n.left)
            yield n.val
            yield from inorder(n.right)

        return list(inorder(root))
Example #10
0
    def merge_two_bsts(self, root1: List[int], root2: List[int]) -> TreeNode:
        root1 = TreeNode.deserialize(root1)
        root2 = TreeNode.deserialize(root2)

        a1, a2 = [], []

        def inorder(n, a):
            if n is None: return
            inorder(n.left, a)
            a.append(n)
            inorder(n.right, a)

        def merge(a1, a2):
            a = []
            l1, l2 = 0, 0
            while l1 < len(a1) and l2 < len(a2):
                if a1[l1].val < a2[l2].val:
                    a.append(a1[l1])
                    l1 += 1
                else:
                    a.append(a2[l2])
                    l2 += 1
            while l1 < len(a1):
                a.append(a1[l1])
                l1 += 1
            while l2 < len(a2):
                a.append(a2[l2])
                l2 += 1
            return a

        def bst(l, r, a):
            if l > r: return None
            mid = (r - l) // 2 + l
            n = a[mid]
            n.left = bst(l, mid - 1, a)
            n.right = bst(mid + 1, r, a)
            return n

        inorder(root1, a1)
        inorder(root2, a2)
        return bst(0, len(a1) + len(a2) - 1, merge(a1, a2))
Example #11
0
 def binary_tree_inorder_traversal(
         self, root: typing.List[int]) -> typing.List[int]:
     root = TreeNode.deserialize(root)
     s, t, res = [], root, []
     while s or t:
         while t:
             s.append(t)
             t = t.left
         t = s.pop()
         res.append(t.val)
         t = t.right
     return res
    def check_completeness_of_a_binary_tree(
            self, root: typing.List[int]) -> typing.List[int]:
        root = TreeNode.deserialize(root)

        if root is None: return True
        q = collections.deque([root])
        while q:
            n = q.popleft()
            if n is None: break
            q.append(n.left)
            q.append(n.right)
        return not any(q)
Example #13
0
    def insert_into_a_binary_search_tree(self, root: List[int],
                                         val: int) -> TreeNode:
        root = TreeNode.deserialize(root)

        def inorder(n):
            if n is None: return TreeNode(val)
            if val < n.val:
                n.left = inorder(n.left)
            else:
                n.right = inorder(n.right)
            return n

        return inorder(root)
Example #14
0
    def binary_tree_inorder_traversal(
            self, root: typing.List[int]) -> typing.List[int]:
        root = TreeNode.deserialize(root)
        res = []

        def inorder(n):
            if n is None: return
            inorder(n.left)
            res.append(n.val)
            inorder(n.right)

        inorder(root)
        return res
Example #15
0
    def binary_tree_postorder_traversal(self, root: List[int]) -> TreeNode:
        root = TreeNode.deserialize(root)

        res = []

        def postorder(n):
            if n is None: return
            postorder(n.left)
            postorder(n.right)
            res.append(n.val)

        postorder(root)
        return res
Example #16
0
 def binary_tree_level_order_traversal(self,
                                       root: typing.List[int]) -> TreeNode:
     root = TreeNode.deserialize(root)
     if root is None: return []
     q = collections.deque([(0, root)])
     result = []
     while q:
         l, node = q.popleft()
         while len(result) <= l:
             result.append([])
         result[l].append(node.val)
         if node.left: q.append((l + 1, node.left))
         if node.right: q.append((l + 1, node.right))
     return result
Example #17
0
    def binary_tree_postorder_traversal(self, root: List[int]) -> TreeNode:
        root = TreeNode.deserialize(root)

        if not root: return []
        s, s1 = [root], []
        while s:
            n = s.pop()
            s1.append(n)
            if n.left is not None:
                s.append(n.left)
            if n.right is not None:
                s.append(n.right)

        return [n.val for n in reversed(s1)]
Example #18
0
    def single_value_tree(self, root: List[int]) -> TreeNode:
        root = TreeNode.deserialize(root)

        c = 0

        def postord(t):
            nonlocal c
            if t is None: return set()
            total = postord(t.left) | postord(t.right) | set([t.val])
            if len(total) == 1:
                c += 1
            return total

        postord(root)
        return c
Example #19
0
    def upside_down(self, root: List[int]) -> TreeNode:
        root = TreeNode.deserialize(root)

        if not root: return None

        def upside_down(n):
            if n.left == n.right == None:
                return n
            new_root = upside_down(n.left)
            n.left.right = n
            n.left.left = n.right
            n.right = n.left = None
            return new_root

        return upside_down(root)
Example #20
0
    def split_bst(self, root: List[int], V: int) -> List[List[int]]:
        root = TreeNode.deserialize(root)

        def preorder(node):
            if node is None: return (None, None)
            if node.val <= V:
                left, right = preorder(node.right)
                node.right = left
                return (node, right)
            else:
                left, right = preorder(node.left)
                node.left = right
                return (left, node)

        left, right = preorder(root)
        return [TreeNode.serialize(left), TreeNode.serialize(right)]
Example #21
0
 def binary_tree_level_order_traversal(self,
                                       root: typing.List[int]) -> TreeNode:
     root = TreeNode.deserialize(root)
     if not root: return []
     q = collections.deque([root])
     result = []
     while q:
         l = len(q)
         temp = []
         for i in range(l):
             node = q.popleft()
             temp.append(node.val)
             if node.left is not None: q.append(node.left)
             if node.right is not None: q.append(node.right)
         result.append(temp)
     return result
    def binary_tree_paths(self, root: List[int]) -> List[str]:
        root = TreeNode.deserialize(root)

        def preorder(n, slate):
            if n is None:
                return
            slate.append(n.val)
            if n.left == n.right == None:
                res.append('->'.join(map(str, slate)))
            else:
                preorder(n.left, slate)
                preorder(n.right, slate)
            slate.pop()

        res = []
        preorder(root, [])
        return res
Example #23
0
    def binary_tree_preorder_traversal(
            self, root: typing.List[int]) -> typing.List[int]:
        root = TreeNode.deserialize(root)

        if not root: return []

        def preorder(root):
            s = [root]
            while s:
                n = s.pop()
                yield n.val
                if n.right is not None:
                    s.append(n.right)
                if n.left is not None:
                    s.append(n.left)

        return list(preorder(root))
Example #24
0
 def insert_into_a_binary_search_tree(self, root: List[int],
                                      val: int) -> TreeNode:
     root = TreeNode.deserialize(root)
     new_node = TreeNode(val)
     if root is None: return new_node
     prev = None
     cur = root
     while cur is not None:
         prev = cur
         if val < cur.val:
             cur = cur.left
         else:
             cur = cur.right
     if prev.val > val:
         prev.left = new_node
     else:
         prev.right = new_node
     return root
Example #25
0
    def upside_down(self, root: List[int]) -> TreeNode:
        root = TreeNode.deserialize(root)

        if not root: return None
        cur, s = root, [root]
        while cur.left is not None:
            cur = cur.left
            s.append(cur)

        new_root = cur = s.pop()
        while s:
            n = s.pop()
            cur.left = n.right
            cur.right = n
            n.left = n.right = None
            cur = n

        return new_root
Example #26
0
    def path_sum_ii(self, root: typing.List[int],
                    sum: int) -> typing.List[typing.List[int]]:
        root = TreeNode.deserialize(root)
        res = []

        def dfs(root, slate, cur):
            if root is None: return
            if root.left is None and root.right is None:
                if cur + root.val == sum:
                    res.append(slate[:] + [root.val])
                    return
            slate.append(root.val)
            dfs(root.left, slate, cur + root.val)
            dfs(root.right, slate, cur + root.val)
            slate.pop()

        dfs(root, [], 0)
        return res
    def boundary_of_binary_tree(self, root: List[int]) -> TreeNode:
        root = TreeNode.deserialize(root)
        res = []

        def preord(node, isleft, isright):
            if node is None: return

            if isleft: res.append(node.val)
            if (isleft == isright == False) and (node.left == node.right ==
                                                 None):
                res.append(node.val)

            preord(node.left, isleft, isright and node.right is None)
            preord(node.right, isleft and node.left is None, isright)

            if isright: res.append(node.val)

        if not root: return []
        res.append(root.val)
        preord(root.left, True, False)
        preord(root.right, False, True)
        return res
Example #28
0
    def second_minimum_node_in_a_binary_tree(self, root: List[int]) -> int:
        root = TreeNode.deserialize(root)

        # Root has to be min1, since node value has to be the smaller node.
        # So root value will be the leftest node value
        def pre_order(t):
            nonlocal min2
            # base
            if t is None: return

            # rec
            # current
            if min1 < t.val < min2:
                min2 = t.val

            # left/right if current is same as min1
            # keep looking for min2
            if min1 == t.val:
                pre_order(t.left)
                pre_order(t.right)

        min1, min2 = root.val, float("inf")
        pre_order(root)
        return min2 if min2 < float("inf") else -1
    def all_nodes_distance_k_in_binary_tree(self, root: List[List[int]],
                                            target: int, K: int) -> List[int]:
        root = TreeNode.deserialize(root)

        if not root: return []
        g = collections.defaultdict(list)

        def preorder(n, parent):
            if n is None:
                return

            g[n.val]
            if parent:
                g[parent.val].append(n.val)
                g[n.val].append(parent.val)
            preorder(n.left, n)
            preorder(n.right, n)

        preorder(root, None)

        # bfs
        q = collections.deque([target])
        visited = [True if i == target else False for i in range(len(g))]
        count = 0
        while q:
            print(q)
            if count == K: return list(q)
            l = len(q)
            for _ in range(l):
                v = q.popleft()
                for nv in g[v]:
                    if not visited[nv]:
                        visited[nv] = True
                        q.append(nv)
            count += 1
        return []