class Solution:
    def isCompleteTree(self, root: TreeNode) -> bool:
        queue = deque([root])
        while True:
            currNode = queue.popleft()
            if not currNode.left:
                if currNode.right:
                    return False
                else:  # Found the first leaf node.
                    break

            queue.append(currNode.left)
            if not currNode.right:  # Found the parent of the first leaf node.
                break

            queue.append(currNode.right)

        # From this moment, we have two cases:
        # 1. When it jumps from the first leaf node, all the following node
        #   in the remaining queue should not have any child node.
        # 2. When it jumps from the parent of the first leaf node, then it
        #   also means all the following node the remaining queue should
        #   not have any child node.
        return not any(node.left or node.right for node in queue)


root = TreeNode(1)
root.create_tree({1: (2, 3), 2: (None, None), 3: (7, 8)})
print(Solution().isCompleteTree(root))
Esempio n. 2
0
class Solution:
    def addOneRow(self, root: TreeNode, v: int, d: int) -> TreeNode:
        """
        Traverse the original tree level by level.
        """
        if d == 1:
            newRoot = TreeNode(v)
            newRoot.left = root
            return newRoot

        currNodes = [root]
        for _ in range(2, d):  # Get all the nodes on the d - 1 level.
            currNodes = [
                x for currNode in currNodes
                for x in (currNode.left, currNode.right) if x
            ]

        for currNode in currNodes:
            left, right = currNode.left, currNode.right
            currNode.left = TreeNode(v)
            currNode.right = TreeNode(v)
            currNode.left.left = left
            currNode.right.right = right

        return root


root = TreeNode(4)
root.create_tree({4: (2, 6), 2: (3, 1), 6: (5, None)})
print(Solution().addOneRow(root, 1, 2).print_tree())
"""
https://leetcode.com/problems/maximum-difference-between-node-and-ancestor/
"""

from test_helper import TreeNode


class Solution:
    def maxAncestorDiff(self, root: TreeNode) -> int:
        def check(curr: TreeNode, currMax: int, currMin: int) -> int:
            if not curr:
                return currMax - currMin

            nextMax = max(currMax, curr.val)
            nextMin = min(currMin, curr.val)
            return max(check(curr.left, nextMax, nextMin),
                       check(curr.right, nextMax, nextMin))

        return check(root, root.val, root.val)


root = TreeNode(8)
root.create_tree({
    8: (3, 10),
    3: (1, 6),
    6: (4, 7),
    10: (None, 14),
    14: (None, 13)
})
print(Solution().maxAncestorDiff(root))
Esempio n. 4
0
class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        """
        Use level by level traverse.
        """
        if not root:  # Empty tree.
            return 0

        totalSum, queue = 0, deque([(root, root.val)])
        while queue:
            node, currSum = queue.popleft()
            if not node.left and not node.right:
                totalSum += currSum
                continue

            if node.left:
                queue.append((node.left, currSum * 10 + node.left.val))

            if node.right:
                queue.append((node.right, currSum * 10 + node.right.val))

        return totalSum


givenDict = {
    1: (2, 3)
}
root = TreeNode(1)
root.create_tree(givenDict)
print(Solution().sumNumbers(root))
        # Calculate the last level.
        maxWidth = max(maxWidth, currEnd - currStart + 1)

        return maxWidth

    def widthOfBinaryTree2(self, root: TreeNode) -> int:
        """
        Same idea with much shorter form.
        """
        if not root:
            return 0

        nodesOnEachLevel = [(1, root)]  # (index, node)
        maxWidth = 1
        while nodesOnEachLevel:
            maxWidth = max(
                maxWidth, nodesOnEachLevel[-1][0] - nodesOnEachLevel[0][0] + 1)

            nodesOnEachLevel = [
                nextItem for preIdx, preNode in nodesOnEachLevel
                for nextItem in enumerate((preNode.left, preNode.right),
                                          start=preIdx << 1) if nextItem[1]
            ]

        return maxWidth


root = TreeNode(1)
root.create_tree({1: (2, 3), 2: (4, 5), 3: (None, 7)})
print(Solution().widthOfBinaryTree(root))
Esempio n. 6
0
from test_helper import TreeNode

from typing import List


class Solution:
    def printTree(self, root: TreeNode) -> List[List[str]]:
        def calc_height(root: TreeNode) -> int:
            if not root:
                return 0

            return 1 + max(calc_height(root.left), calc_height(root.right))

        def fill(currNode: TreeNode, r: int, start: int, end: int) -> None:
            if currNode:
                m = start + ((end - start) >> 1)
                rslt[r][m] = str(currNode.val)
                fill(currNode.left, r + 1, start, m - 1)
                fill(currNode.right, r + 1, m + 1, end)

        R = calc_height(root)
        C = (1 << R) - 1
        rslt = [[''] * C for _ in range(R)]
        fill(root, 0, 0, C - 1)
        return rslt


root = TreeNode(1)
root.create_tree({1: (2, 3), 2: (None, 4)})
print(Solution().printTree(root))
Esempio n. 7
0
"""
https://leetcode.com/problems/convert-bst-to-greater-tree/
"""

from test_helper import TreeNode


class Solution:
    def convertBST(self, root: TreeNode) -> TreeNode:
        currNode, stack, pre = root, [], 0
        while currNode or stack:
            while currNode:
                stack.append(currNode)
                currNode = currNode.right

            currNode = stack.pop()
            currNode.val += pre
            pre = currNode.val
            currNode = currNode.left

        return root


root = TreeNode(5)
root.create_tree({5: (2, 13)})
print(Solution().convertBST(root))
"""
https://leetcode.com/problems/insert-into-a-binary-search-tree/
"""

from test_helper import TreeNode


class Solution:
    def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
        if not root:
            return TreeNode(val)

        if val < root.val:
            root.left = self.insertIntoBST(root.left, val)
        else:
            root.right = self.insertIntoBST(root.right, val)

        return root


root = TreeNode(4)
root.create_tree({4: (2, 7), 2: (1, 3)})
print(Solution().insertIntoBST(root, 5).print_tree())
Esempio n. 9
0
        """
        Taking advantage of BST and inorder traversal.
        """
        n1, n2, s1, s2, rslt = root1, root2, [], [], []
        while n1 or n2 or s1 or s2:
            while n1:
                s1.append(n1)
                n1 = n1.left

            while n2:
                s2.append(n2)
                n2 = n2.left

            if not s2 or (s1 and s1[-1].val <= s2[-1].val):
                n1 = s1.pop()
                rslt.append(n1.val)
                n1 = n1.right
            else:
                n2 = s2.pop()
                rslt.append(n2.val)
                n2 = n2.right

        return rslt


root1 = TreeNode(0)
root1.create_tree({0: (None, 59), 59: (57, 90)})
root2 = TreeNode(60)
root2.create_tree({60: (17, 74), 17: (6, 20), 74: (63, 97), 97: (95, None)})
print(list(Solution()._in_order(root1)))
Esempio n. 10
0
        For a perfect binary tree, if its height is h, the total nodes
        it has is 2^0 + 2^1 + ... + 2^(h - 1) = 2^0 * (1 - 2^h) / (1 - 2)
        = 2^h - 1. 
        """
        nodeCnt, currNode, rootHeight = 0, root, self.get_height(root)
        while currNode:
            leftHeight = rootHeight - 1
            rightHeight = self.get_height(currNode.right)
            if leftHeight == rightHeight:
                # The left sub tree is a perfect binary tree.
                # So the total nodes in root and its left sub tree is:
                # 1 + 2 ^ h - 1 = 2 ^ h.
                nodeCnt += 1 << leftHeight
                currNode = currNode.right
            else:
                # The right sub tree is a perfect binary tree.
                # So the total nodes in root and its right sub tree is:
                # 1 + 2 ^ h - 1 = 2 ^ h.
                nodeCnt += 1 << rightHeight
                currNode = currNode.left

            rootHeight -= 1

        return nodeCnt


root = TreeNode(1)
root.create_tree({1: (2, 3), 2: (4, 5), 3: (6, None)})
print(Solution().countNodes(root))
Esempio n. 11
0
        """
        Use stack to rebuild the tree.
        """
        if not data:
            return None

        stack, vals = [], data.split()
        root = currNode = TreeNode(int(vals[0]))
        for i in range(1, len(vals)):
            val = int(vals[i])
            if val < currNode.val:
                currNode.left = TreeNode(val)
                stack.append(currNode)
                currNode = currNode.left
            else:
                while stack and stack[-1].val < val:
                    currNode = stack.pop()

                currNode.right = TreeNode(val)
                currNode = currNode.right

        return root


root = TreeNode(5)
root.create_tree({5: (3, 6), 3: (2, 4), 2: (1, None)})
c = Codec()
s = c.serialize(root)
print(s)
print(c.deserialize(s).print_tree())
Esempio n. 12
0
            1. The maximum money when the current node is not robbed.
            2. The maximum money when the current node is robbed.
            """
            if not currNode:  # Cannot rob anything.
                return [0] * 2

            left = rob_each(currNode.left)
            right = rob_each(currNode.right)

            # Calculate the max money when the current node is not robbed.
            # We could either rob its left or right node or not rob them.
            # Just get the maximum money from both cases.
            m1 = max(left) + max(right)

            # Calculate the max money when the current node is robbed.
            # In this case we should not rob either its left or right node.
            m2 = currNode.val + left[0] + right[0]

            return [m1, m2]

        return max(rob_each(root))


root = TreeNode(1)
root.create_tree(givenDict={
    1: (2, 3),
    2: (4, 5),
    3: (6, 7)
})
print(Solution().rob(root))
Esempio n. 13
0
class Solution:
    def deleteNode(self, root: TreeNode, key: int) -> TreeNode:
        if not root:
            return None

        if root.val < key:
            root.right = self.deleteNode(root.right, key)
        elif root.val > key:
            root.left = self.deleteNode(root.left, key)
        else:  # Root is the target node to be deleted.
            if not root.left:
                return root.right
            elif not root.right:
                return root.left
            else:
                # Update the root value with the minimum value on its right
                # sub tree, then delete the old minimum tree node.
                curr = root.right
                while curr.left:
                    curr = curr.left

                root.val = curr.val
                root.right = self.deleteNode(root.right, root.val)

        return root


root = TreeNode(5)
root.create_tree({5: (3, 6), 3: (2, 4), 6: (None, 7)})
print(Solution().deleteNode(root, 3).print_tree())