""" def dfs(node): # dfs returns a list of two numbers: # dp[0] denotes the max profit of the subtree rooting at node WITHOUT robbing node # dp[1] denotes the max profit of the subtree rooting at node WITH robbing node if node is None: return [0, 0] left = dfs(node.left) right = dfs(node.right) dp = [0, 0] # if node has not been robbed, then its children can be either robbed or not dp[0] = max(left[0], left[1]) + max(right[0], right[1]) # if node has been robbed, then its children must not be robbed dp[1] = node.val + left[0] + right[0] return dp # res[0] is the max profit if root has been robbed # res[1] is the max profit if root has not been robbed res = dfs(root) return max(res) test = list2binary_tree([3, 2, 3, None, 3, None, 1]) print(rob(test))
return res def inorderTraversal_iterative_alt(root): """ Iterative, but the stack only contains TreeNode Time: O(n) Space: O(H) """ res = [] stack = [] curr_node = root while stack or curr_node: # push all the left nodes to the current node in (right children not included) while curr_node: stack.append(curr_node) curr_node = curr_node.left # then popped node must be the left most node in the unvisited nodes curr_node = stack.pop() # at this point all curr_node's left branch has been visited, visit curr_node res.append(curr_node.val) # next move to the right branch of curr_node and start to visit its left branch (in the next iteration) curr_node = curr_node.right return res test = list2binary_tree([1, None, 2, 3]) print(inorderTraversal(test)) print(inorderTraversal_iterative(test))
def levelOrderBottom(root): """ BFS with deque to store the results (no need to reverse rhe results in the end) Time: O(n) Space: O(n) """ if not root: return root res = deque() que = deque([(root, 1)]) while que: curr_node, level = que.popleft() if curr_node.left: que.append((curr_node.left, level + 1)) if curr_node.right: que.append((curr_node.right, level + 1)) if len(res) < level: res.appendleft([curr_node.val]) else: res[0].append(curr_node.val) return res test = list2binary_tree([3, 9, 20, None, None, 15, 7]) print(levelOrderBottom(test))
def distanceK(root, target, K): """ Make target the new root then run BFS on the new graph Time: O(n) Construction of the adj dict (longer) and BFS Space: O(n) n - number of nodes; the adjacency dict has the size of 2*E, E = n - 1, the number of edges """ # Note that here every node has a unique value # target should be an int, if it's a TreeNode, input target.val in BFS queue = deque() neighbour_dict = defaultdict(list) queue.append(root) while queue: curr_node = queue.popleft() if curr_node is not None: if curr_node.left is not None: neighbour_dict[curr_node.val].append(curr_node.left.val) neighbour_dict[curr_node.left.val].append(curr_node.val) if curr_node.right is not None: neighbour_dict[curr_node.val].append(curr_node.right.val) neighbour_dict[curr_node.right.val].append(curr_node.val) queue.append(curr_node.left) queue.append(curr_node.right) return BFS(target, neighbour_dict, K) test_tree = list2binary_tree([3, 5, 1, 6, 2, 0, 8, None, None, 7, 4]) test_t = 5 test_k = 2 print(distanceK(test_tree, test_t, test_k))
from utils import list2binary_tree def diameterOfBinaryTree(root): def get_children_length(node, curr_max): if not node: return -1, curr_max left_len, curr_max = get_children_length(node.left, curr_max) right_len, curr_max = get_children_length(node.right, curr_max) curr_max = max(curr_max, left_len + right_len + 2) return max(left_len + 1, right_len + 1), curr_max _, max_len = get_children_length(root, 0) return max_len test = [4,-7,-3,None,None,-9,-3,9,-7,-4,None,6,None,-6,-6,None,None,0,6,5,None,9,None,None,-1,-4,None,None,None,-2] # test = [1,2,3,4,5] test_tree = list2binary_tree(test) print(diameterOfBinaryTree(test_tree))
# Append (node, level) to the stack stack.append((root, 1)) # res is for the final answer res = [] while stack: # or curr_node, level = que.popleft() curr_node, level = stack.pop() if curr_node.left: stack.append((curr_node.left, level + 1)) if curr_node.right: stack.append((curr_node.right, level + 1)) # if visiting a node from a new level for the first time if len(res) < level: res.append(deque([curr_node.val])) # else the deque for the level already exists, append (left or right) to it else: # if we are using queue instead of stack here, swap the if and else conditions if level % 2 == 0: res[level - 1].append(curr_node.val) else: res[level - 1].appendleft(curr_node.val) return res test = list2binary_tree( [1, 2, 3, 4, 5, 6, 7, 8, None, None, None, 9, 10, None, None]) print(zigzagLevelOrder_dfs(test))
# update max_depth only if curr_node an actual node, so this will stop at the leaves if curr_depth > max_depth: max_depth = curr_depth return max_depth def maxDepth_BFS(root): """ Breadth first search Time: O(n) Space: O(n) """ # similar to DFS, just replace the stack with a queue from collections import deque que = deque() max_depth = 0 que.append((root, 1)) while que: curr_node, curr_depth = que.popleft() if curr_node: que.append((curr_node.left, curr_depth + 1)) que.append((curr_node.right, curr_depth + 1)) if curr_depth > max_depth: max_depth = curr_depth return max_depth test_tree = list2binary_tree([1, 2, 3, None, None, 4, 5, 6, 7, 8]) print(maxDepth_BFS(test_tree))
else: return False return True def isSubtree(s, t): """ For each node in s, check if it is the same as t, if it is, then check the subtree Time: O(mn) in the worst case, invoke isEqual for every node in s Space: O(n) n - number of nodes in the tree whose root is s_node """ s_stack = [s] while s_stack: curr_node = s_stack.pop() if curr_node is not None: if curr_node.val == t.val and isEqual(curr_node, t): return True s_stack.append(curr_node.left) s_stack.append(curr_node.right) return False test_s_1 = list2binary_tree([3, 4, 5, 1, 2]) test_t_1 = list2binary_tree([4, 1, 2]) test_s_2 = list2binary_tree([3, 4, 5, 1, None, 2]) test_t_2 = list2binary_tree([3, 1, 2]) print(isSubtree(test_s_2, test_t_2))
return len(self.stack) > 0 def next(self): """ @return the next smallest number Time: O(1) Space: O(N) for calling the sorted_nodes """ return self.sorted_nodes.pop() def hasNext(self): """ @return whether we have a next smallest number Time: O(1) Space: O(N) for calling the sorted_nodes """ return len(self.sorted_nodes) > 0 test = list2binary_tree([7, 3, 15, None, None, 9, 20]) a = BSTIterator(test) print(a.next()) print(a.next()) print(a.hasNext()) print(a.next()) print(a.hasNext()) print(a.next()) print(a.hasNext()) print(a.next()) print(a.hasNext())