Tree

[1]:
import IPython; IPython.display.HTML('''<script>code_show=true; function code_toggle() { if (code_show){ $('div.nbinput').show(); } else { $('div.nbinput').hide(); } code_show = !code_show} $( document ).ready(code_toggle);</script><form action="javascript:code_toggle()"><input type="submit" value="Click here to toggle on/off the raw code."></form>''')
[1]:

94. Binary Tree Inorder Traversal

Easy

Given the root of a binary tree, return the inorder traversal of its nodes’ values.

inorder_1.jpg

Example 1:

Input: root = [1,null,2,3]
Output: [1,3,2]

Constraints:

The number of nodes in the tree is in the range [0, 100].
-100 <= Node.val <= 100

Follow up: Recursive solution is trivial, could you do it iteratively?

[1]:
# recursion

def inorderTraversal(root):
    if not root:
        return []
    else:
        return inorderTraversal(root.left) + [root.val] + inorderTraversal(root.right)

100. Same Tree

Easy

Given the roots of two binary trees p and q, write a function to check if they are the same or not.

Two binary trees are considered the same if they are structurally identical, and the nodes have the same value.

Example 1:

image.png

Input: p = [1,2,3], q = [1,2,3]
Output: true

Constraints:

The number of nodes in both trees is in the range [0, 100].
-10^4 <= Node.val <= 10^4
[1]:
# recursion

def isSameTree(p, q):
    if p is None and q is None:
        return True
    elif p or q:
        return False
    else:
        return isSameTree(p.left, q.left) and isSameTree(p.right, q.right) and (p.val == q.val)

102. Binary Tree Level Order Traversal

Medium

Given the root of a binary tree, return the level order traversal of its nodes’ values. (i.e., from left to right, level by level).

Example 1:

image102.png

Input: root = [3,9,20,null,null,15,7]
Output: [[3],[9,20],[15,7]]

Constraints:

The number of nodes in the tree is in the range [0, 2000].
-1000 <= Node.val <= 1000
[ ]:
# BFS

from collections import deque

def levelOrder(root):
    q = deque()
    if root:
        q.append(root)

    res = []
    while q:
        level = []
        for _ in range(len(q)):
            node = q.popleft()
            level.append(node.val)
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)

        res.append(level)
    return res

814. Binary Tree Pruning

Medium

Given the root of a binary tree, return the same tree where every subtree (of the given tree) not containing a 1 has been removed.

A subtree of a node node is node plus every node that is a descendant of node.

Example 1:

1028_2.png

Input: root = [1,null,0,0,1]
Output: [1,null,0,null,1]
Explanation:
Only the red nodes satisfy the property "every subtree not containing a 1".
The diagram on the right represents the answer.

Constraints:

The number of nodes in the tree is in the range [1, 200].
Node.val is either 0 or 1.
[ ]:
# recursion

def pruneTree(root):
    if not root:
        return None

    root.left = pruneTree(root.left)
    root.right = pruneTree(root.right)

    if root.val==0 and (not root.left) and (not root.right):
        return None
    else:
        return root

112. Path Sum

Easy

Given the root of a binary tree and an integer targetSum, return true if the tree has a root-to-leaf path such that adding up all the values along the path equals targetSum.

A leaf is a node with no children.

Example 1:

pathsum1.jpg

Input: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
Output: true
Explanation: The root-to-leaf path with the target sum is shown.

Constraints:

The number of nodes in the tree is in the range [0, 5000].
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
[1]:
# recursion

def hasPathSum(root, targetSum):
    if not root:
        return False

    if (not root.left) and (not root.right):
        return targetSum == root.val
    else:
        return hasPathSum(root.left, targetSum-root.val) or hasPathSum(root.right, targetSum-root.val)

129. Sum Root to Leaf Numbers

Medium

You are given the root of a binary tree containing digits from 0 to 9 only.

Each root-to-leaf path in the tree represents a number.

For example, the root-to-leaf path 1 -> 2 -> 3 represents the number 123.

Return the total sum of all root-to-leaf numbers. Test cases are generated so that the answer will fit in a 32-bit integer.

A leaf node is a node with no children.

Example 1:

num1tree.jpg

Input: root = [1,2,3]
Output: 25
Explanation:
The root-to-leaf path 1->2 represents the number 12.
The root-to-leaf path 1->3 represents the number 13.
Therefore, sum = 12 + 13 = 25.

Constraints:

The number of nodes in the tree is in the range [1, 1000].
0 <= Node.val <= 9
The depth of the tree will not exceed 10.
[ ]:
# recursively returns list of strings like ['12', '13'] and sum them in the end

def numbers(root):
    '''
    Returns a list of strings, for example ['12', '13'].
    '''
    if (not root.left) and (not root.right):
        return [str(root.val)]
    else:
        res = []
        if root and root.left:
            res += [str(root.val) + num for num in self.numbers(root.left)]
        if root and root.right:
            res += [str(root.val) + num for num in self.numbers(root.right)]
        return res

def sumNumbers(root):
    return sum(int(num) for num in numbers(root))
[ ]:
# DFS compute sum given current sum

def dfs(self, root, cur_sum):
    if not root:    # tree [0, 1] will break without this
        return 0

    cur_sum = 10*cur_sum + root.val

    if (not root.left) and (not root.right):
        return cur_sum

    sum_l = dfs(root.left, cur_sum)
    sum_r = dfs(root.right, cur_sum)

    return sum_l + sum_r

def sumNumbers(root):
    return dfs(root, 0)

236. Lowest Common Ancestor of a Binary Tree

Medium

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

Example 2:

image236.png

Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
Output: 5
Explanation: The LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.

Constraints:

The number of nodes in the tree is in the range [2, 10^5].
-10^9 <= Node.val <= 10^9
All Node.val are unique.
p != q
p and q will exist in the tree.
[1]:
# LeetCode 上最快解答:DFS 從下向上(divide and conquer 先遞迴傳回結果再合併)

def lowestCommonAncestor(root, p, q):
    if root in [p, q, None]:
        return root

    left = lowestCommonAncestor(root.left, p, q)
    right = lowestCommonAncestor(root.right, p, q)

    if left and right:
        return root
    elif left:
        return left
    else:
        return right

508. Most Frequent Subtree Sum

Medium

Given the root of a binary tree, return the most frequent subtree sum. If there is a tie, return all the values with the highest frequency in any order.

The subtree sum of a node is defined as the sum of all the node values formed by the subtree rooted at that node (including the node itself).

Example 1:

freq1-tree.jpg

Input: root = [5,2,-3]
Output: [2,-3,4]

Constraints:

The number of nodes in the tree is in the range [1, 10^4].
-10^5 <= Node.val <= 10^5
[ ]:
from collections import defaultdict

def findFrequentTreeSum(root):
    '''
    We need to know the the sum at each node and keep a counter.
    '''
    freq = defaultdict(int)
    def dfs(node):
        if not node:
            return 0
        else:
            subtree_sum = node.val + dfs(node.left) + dfs(node.right)
            freq[subtree_sum] += 1
            return subtree_sum
    dfs(root)
    max_freq = max(freq.values())

    return [s for s, f in freq.items() if freq[s]==max_freq]
[3]:
# my ugly solution -- compute tree of subtree sum first

from collections import defaultdict

def findFrequentTreeSum(root):
    sums = serialize(tree_sum(root))

    freq = defaultdict(int)
    for s in sums:
        freq[s] += 1

    max_freq = max(freq.values())
    return [s for s, f in freq.items() if f==max_freq]

def serialize(root):
    if not root:
        return []
    return serialize(root.left) + [root.val] + serialize(root.right)

def tree_sum(root):
    if (not root) or ((not root.left) and (not root.right)):
        return root

    left = tree_sum(root.left)
    right = tree_sum(root.right)

    root.val += ((left.val if left else 0) + (right.val if right else 0))
    root.left = left
    root.right = right

    return root