Beispiel #1
0
    def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
        # Presumption: Each node of the tree contains a unique value.
        if not inorder:  # Empty tree.
            return None

        root = TreeNode(postorder[-1])
        inIdx, preRoots = -1, [root]
        for currVal in postorder[-2::-1]:
            currRoot, currNode = preRoots[-1], TreeNode(currVal)
            if currRoot.val != inorder[inIdx]:
                # No match to the inorder values, so adding the current node
                # as the right node of the current root.
                currRoot.right = currNode
            else:
                while preRoots and preRoots[-1].val == inorder[inIdx]:
                    # Found match to the inorder values, then keep searching
                    # until arriving at the root that does not match the inorder
                    # values. Then the current node is the left node of
                    # the current root.
                    inIdx -= 1
                    currRoot = preRoots.pop()

                currRoot.left = currNode

            preRoots.append(currNode)

        return root
Beispiel #2
0
    def constructFromPrePost(self, pre: list[int],
                             post: list[int]) -> TreeNode:
        """
        1. Iterate on pre list and create each new node.
        2. Then save the current path to the stack.
        3. Add new node to the left if the previous node has no left child.
        4. Otherwise add right.
        5. Once we come across the same node in pre and post, we pop it
            from the stack and increase the index on post list.
        6. The above is like in the post list, when we visited post[i], all
            the child nodes rooted on post[i] has been visited previously, so
            we could use pre to create new node, then use post to check if
            all the nodes are created.
        """
        stack = [TreeNode(pre[0])]
        iPost = 0
        for iPre in range(1, len(pre)):
            currNode = TreeNode(pre[iPre])
            while stack[-1].val == post[iPost]:
                stack.pop()
                iPost += 1

            if not stack[-1].left:
                stack[-1].left = currNode
            else:
                stack[-1].right = currNode

            stack.append(currNode)

        return stack[0]
 def pruneTree(self, root: TreeNode) -> TreeNode:
     if root:
         root.left = self.pruneTree(root.left)
         root.right = self.pruneTree(root.right)
         if root.val or root.left or root.right:
             # The root node could not be pruned any longer.
             return root
Beispiel #4
0
    def constructMaximumBinaryTree2(self, nums: List[int]) -> TreeNode:
        """
        Instead of finding the maximum number for each sub list every time, we
        simply use a stack which holds the numbers in descending order. Then
        we have:
            1. If the next number is less than the top of the stack, it is
                a candidate right node for the top of the stack, so we set it
                as the right node and also append it to the stack.
            2. Else, we keep popping from the stack until the stack is empty
                or the top of the stack is greater than the next number. Notice
                the last item popped from the stack will be the left node for
                the next number.
        """
        if not nums:
            return None

        stack = []
        for num in nums:
            node, lastPoppedNode = TreeNode(num), None
            while stack and stack[-1].val < num:
                lastPoppedNode = stack.pop()

            node.left = lastPoppedNode
            if stack:
                stack[-1].right = node

            stack.append(node)

        return stack[0]  # The first item in the stack is our root node.
    def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
        if not nums:  # Empty tree.
            return None

        m = (len(nums) - 1) // 2
        root = TreeNode(nums[m])
        root.left = self.sortedArrayToBST(nums[:m])
        root.right = self.sortedArrayToBST(nums[m + 1:])
        return root
    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
Beispiel #7
0
        def do() -> TreeNode:
            currVal = next(vals)
            if currVal == '#':
                return None

            root = TreeNode(int(currVal))
            root.left = do()
            root.right = do()

            return root
        def g(first: int, last: int) -> List[TreeNode]:
            rslt = []
            for root in range(first, last + 1):
                for leftNode in g(first, root - 1):
                    for rightNode in g(root + 1, last):
                        currNode = TreeNode(root)
                        currNode.left = leftNode
                        currNode.right = rightNode
                        rslt.append(currNode)

            return rslt or [None]  # Need to return [None] when rslt is empty.
Beispiel #9
0
    def mergeTrees(self, t1: TreeNode, t2: TreeNode) -> TreeNode:
        if not t1:
            return t2

        if not t2:
            return t1

        t1.val += t2.val
        t1.left = self.mergeTrees(t1.left, t2.left)
        t1.right = self.mergeTrees(t1.right, t2.right)
        return t1
Beispiel #10
0
        def do(start: int, end: int) -> TreeNode:
            if end < start:
                return None

            maxIdx, maxNum = start, nums[start]
            for i in range(start + 1, end + 1):
                if nums[i] > maxNum:
                    maxIdx, maxNum = i, nums[i]

            root = TreeNode(maxNum)
            root.left = do(start, maxIdx - 1)
            root.right = do(maxIdx + 1, end)
            return root
Beispiel #11
0
    def insert(self, v: int) -> int:
        if len(self.currLeaves) == (len(self.currParents) << 1):
            self.currParents = self.currLeaves
            self.currLeaves = []

        parent = self.currParents[len(self.currLeaves) >> 1]
        if parent.left:
            parent.right = TreeNode(v)
            self.currLeaves.append(parent.right)
        else:
            parent.left = TreeNode(v)
            self.currLeaves.append(parent.left)

        return parent.val
        def check(n: int) -> list[TreeNode]:
            if n not in memo:
                rslt = []
                for i in range(n):
                    j = n - 1 - i
                    for left in check(i):
                        for right in check(j):
                            root = TreeNode(0)
                            root.left = left
                            root.right = right
                            rslt.append(root)

                memo[n] = rslt

            return memo[n]
Beispiel #13
0
        def do(start: int, end: int) -> TreeNode:
            if start > end:
                return None

            if start == end:
                return TreeNode(preorder[start])

            rootVal = preorder[start]
            left = start + 1
            while left <= end and preorder[left] < rootVal:
                left += 1

            root = TreeNode(rootVal)
            root.left = do(start + 1, left - 1)
            root.right = do(left, end)
            return root
    def create_tree(self, l: int, r: int) -> TreeNode:
        if l > r:
            return None

        m = (l + r) // 2

        left = self.create_tree(l, m - 1)

        root = TreeNode(self.currNodeInList.val)
        root.left = left

        self.currNodeInList = self.currNodeInList.next

        root.right = self.create_tree(m + 1, r)

        return root
Beispiel #15
0
    def deserialize(self, data: str) -> TreeNode:
        """
        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
    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
    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
    def allPossibleFBT(self, n: int) -> list[TreeNode]:
        def check(n: int) -> list[TreeNode]:
            if n not in memo:
                rslt = []
                for i in range(n):
                    j = n - 1 - i
                    for left in check(i):
                        for right in check(j):
                            root = TreeNode(0)
                            root.left = left
                            root.right = right
                            rslt.append(root)

                memo[n] = rslt

            return memo[n]

        if not n & 1:  # Must have odd nodes to form full binary tree.
            return []

        memo = {0: [], 1: [TreeNode(0)]}

        return check(n)
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())
Beispiel #20
0

class Solution:
    def pseudoPalindromicPaths(self, root: TreeNode) -> int:
        def search(currNode: TreeNode) -> None:
            if currNode:
                freqs[currNode.val - 1] += 1
                if not (currNode.left or currNode.right):
                    # Reach a leaf node.
                    if sum(f & 1 for f in freqs) <= 1:
                        self.paths += 1
                else:
                    search(currNode.left)
                    search(currNode.right)

                freqs[currNode.val - 1] -= 1  # Restore to search other paths.

        freqs = [0] * 9
        self.paths = 0
        search(root)
        return self.paths


r = TreeNode(2)
r.left = TreeNode(3)
r.right = TreeNode(1)
r.left.left = TreeNode(3)
r.left.right = TreeNode(1)
r.right.right = TreeNode(1)
print(Solution().pseudoPalindromicPaths(r))
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))
Beispiel #22
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))
"""
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))
Beispiel #24
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))
        # 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))
https://leetcode.com/problems/flatten-binary-tree-to-linked-list/
"""

from test_helper import TreeNode


class Solution:
    def flatten(self, root: TreeNode) -> None:
        currNode, preRights = root, []
        while currNode or preRights:
            while currNode and currNode.left:
                if currNode.right:
                    preRights.append(currNode.right)

                currNode.right = currNode.left
                currNode.left = None
                currNode = currNode.right

            if not currNode.right and preRights:
                currNode.right = preRights.pop()

            currNode = currNode.right


givenDict = {1: (2, 5), 2: (3, 4), 5: (None, 6)}

root = TreeNode(1)
root.create_tree(givenDict)
Solution().flatten(root)
print(root.print_tree())
"""
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())
Beispiel #28
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))
Beispiel #29
0
        def check(currNode: TreeNode) -> int:
            if not currNode:
                return 0

            leftMax, rightMax = check(currNode.left), check(currNode.right)
            leftSame = rightSame = 0
            if currNode.left and currNode.left.val == currNode.val:
                leftSame = 1 + leftMax

            if currNode.right and currNode.right.val == currNode.val:
                rightSame = 1 + rightMax

            self.rslt = max(self.rslt, leftSame + rightSame)

            return max(leftSame, rightSame)

        self.rslt = 0
        check(root)
        return self.rslt


root = TreeNode(1)
root.right = TreeNode(1)
node = root.right
node.left = TreeNode(1)
node.right = TreeNode(1)
node.left.left = TreeNode(1)
node.left.right = TreeNode(1)
node.right.left = TreeNode(1)
print(Solution().longestUnivaluePath(root))
Beispiel #30
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)))