"""

    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))
Beispiel #6
0
    # 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))
Beispiel #8
0
        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())