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 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
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 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
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 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]
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
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())
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))
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))
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())
""" 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)))