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
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 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 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 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
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.
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
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 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]
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
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())
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))
""" 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))
# Save the predecessor node to the right sub tree's right # leaf node. node.right = currNode currNode = currNode.left else: # leaf node stores the predecessor node. node.right = None # Recover tree shape. chkNode = currNode currNode = currNode.right if chkNode: if preNode and preNode.val > chkNode.val: errNodes.append(preNode) errNodes.append(chkNode) preNode = chkNode # Swap the value from the error nodes. if not errNodes: # No errors found. return errNodes[0].val, errNodes[-1].val = errNodes[-1].val, errNodes[0].val givenDict = { 3: (1, 4), 4: (2, None) } root = TreeNode(3) root.create_tree(givenDict) Solution().recoverTree(root)
""" https://leetcode.com/problems/binary-tree-pruning/ """ from test_helper import TreeNode class Solution: 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 root = TreeNode(1) root.right = TreeNode(0) root.right.left = TreeNode(0) root.right.right = TreeNode(1) print(Solution().pruneTree(root).print_tree())
""" 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))
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))
""" 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)))