Tree Questions: Li Yin February 7, 2019
Tree Questions: Li Yin February 7, 2019
Li Yin1
February 7, 2019
1
www.liyinscience.com
ii
Tree Questions(10%)
When we first go for interviews, we may find tree and graph problems intim-
idating and challenging to solve within 40 mins normal interview window.
This might because of our neglinance of the concept of Divide and Conquer
or due to the recursion occurrence in tree-related problems. However, at
this point, we have already studied the concepts of various trees, divide and
conquer, and solved quite a large amount of related questions in previous
chapters in this part. We will find out studing this chapter can be real easy
compared with the Dynamic programming questions because the consistent
principle to solve tree questions. The principle is to solve problems within
tree traversal, either recursively or iteratively, in either of two ways:
iii
iv TREE QUESTIONS(10%)
current node, we “merge“ the results of the subtree to gain the result
for current node. This also requires us to define the return value for
edge cases: normally would be empty node and/or leaves.
1 def treeTraversalDivideConquer ( root ) :
2 i f node i s empty o r node i s a l e a f node :
3 return base r e s u l t
4 # divide
5 l e f t r e s u l t = treeTraversalDivideConquer ( root . l e f t )
6 right r e s u l t = treeTraversalDivideConquer ( root . right )
7
8 # co nqu er
9 merge t h e l e f t and r i g h t r e s u l t with t h e c u r r e n t node
10 r e t u r n merged r e s u l t o f c u r r e n t node
The difficulty of these problems are decided by the merge operation, and
how many different variables we need to return to decide the next merge
operation. However, if we don’t like using the recursive function, we can use
levelorder traversal implemented with Queue.
Binary tree and Binary Searching tree are the most popular type of
questions among interviews. They each take nearly half and half of all the
tree questions. We would rarely came into the Segment Tree or Trie, but if
you have extra time it will help you learn more if you would study thest two
types too.
1. Tree Traversal;
4. Tree Path
3
/ \
9 20
/ \
15 7
return i t s z i g z a g l e v e l order t r a v e r s a l as :
[
[3] ,
[20 ,9] ,
[15 ,7]
]
20 q = tmp
21 i f i % 2 == 0 :
22 ans += [ tmpAns ]
23 else :
24 ans += [ tmpAns [ : : − 1 ] ]
25 i += 1
26 r e t u r n ans
0.2 105. Construct Binary Tree from Preorder and Inorder Traver-
sal. Given preorder and inorder traversal of a tree, construct the bi-
nary tree. Note:You may assume that duplicates do not exist in the
tree.
For example , g i v e n p r e o r d e r = [ 3 , 9 , 2 0 , 1 5 , 7 ] , i n o r d e r =
[9 ,3 ,15 ,20 ,7]
Return t h e f o l l o w i n g b i n a r y t r e e :
3
/ \
9 20
/ \
15 7
20 continue
21 i f bLeft :
22 l e f t i n o r d e r . append ( e )
23 else :
24 r i g h t i n o r d e r . append ( e )
25 leftset , rightset = set ( leftinorder ) , set (
rightinorder )
26 leftpreorder , rightpreorder = [ ] , [ ]
27 for e in preorder [ 1 : ] :
28 i f e in l e f t s e t :
29 l e f t p r e o r d e r . append ( e )
30 else :
31 r i g h t p r e o r d e r . append ( e )
32
33 #c onq uer
34 node . l e f t =h e l p e r ( l e f t p r e o r d e r , l e f t i n o r d e r )
35 node . r i g h t= h e l p e r ( r i g h t p r e o r d e r , r i g h t i n o r d e r )
36 r e t u r n node
37 return helper ( preorder , inorder )
However, the previous code has problem as 203 / 203 test cases passed.
Status: Memory Limit Exceeded. So instead of passing new array, I
use index.
1 def buildTree ( s e l f , preorder , inorder ) :
2 """
3 : type p r e o r d e r : L i s t [ i n t ]
4 : type i n o r d e r : L i s t [ i n t ]
5 : r t y p e : TreeNode
6 """
7 #f i r s t t o d e c i d e t h e r o o t
8 d e f h e l p e r ( pre_l , pre_r , in_l , in_r ) : #[ pre_l , pre_r )
9 i f pre_l>=pre_r o r in_l>=in_r :
10 r e t u r n None
11
12 cur_val = p r e o r d e r [ pre_l ]
13 node = TreeNode ( cur_val )
14 #d i v i d e : now c u t t h e l i s t s i n t o two h a l f s
15 leftinorder = set ()
16 i n o r d e r _ i n d e x = −1
17 f o r i i n r a n g e ( in_l , in_r ) :
18 i f i n o r d e r [ i ]==cur_val :
19 inorder_index = i
20 break
21 l e f t i n o r d e r . add ( i n o r d e r [ i ] )
22 #when l e f t s e t i s empty
23 new_pre_r=pre_l
24 f o r i i n r a n g e ( pre_l +1, pre_r ) :
25 i f preorder [ i ] in l e f t i n o r d e r :
26 new_pre_r = i
27 else :
28 break
29 new_pre_r+=1
30
viii TREE QUESTIONS(10%)
31 #c onq uer
32 node . l e f t =h e l p e r ( pre_l +1, new_pre_r , in_l ,
inorder_index )
33 node . r i g h t= h e l p e r ( new_pre_r , pre_r ,
i n o r d e r _ i n d e x +1 , in_r )
34 r e t u r n node
35 i f not p r e o r d e r o r not i n o r d e r :
36 r e t u r n None
37 return helper (0 , len ( preorder ) ,0 , len ( inorder ) )
0.1.2 Depth/Height/Diameter
In this section, focus on the property related problems of binary tree: in-
cluding depth, height and diameter. We can be asked to validate balanced
binary tree, or the maximum/minimum of these values. The solution is tree
traversal along with some operations along can be used to solve this type of
problems.
1 d e f minDepth ( s e l f , r o o t ) :
2 i f r o o t i s None :
3 return 0
4 q = [ root ]
5 d = 0
6 while q :
7 d += 1
8 f o r node i n q :
9 i f not node . l e f t and not node . r i g h t : #a l e a f
10 return d
11
12 q = [ neigbor for n in q for neigbor in [ n . l e f t , n .
right ] i f neigbor ]
13 return d
Given t h e f o l l o w i n g t r e e [ 3 , 9 , 2 0 , n u l l , n u l l , 1 5 , 7 ] :
3
/ \
9 20
/ \
15 7
Return t r u e .
Example 2 :
x TREE QUESTIONS(10%)
Given t h e f o l l o w i n g t r e e [ 1 , 2 , 2 , 3 , 3 , n u l l , n u l l , 4 , 4 ] :
1
/ \
2 2
/ \
3 3
/ \
4 4
Return f a l s e .
0.5 543. Diameter of Binary Tree (Easy). Given a binary tree, you
need to compute the length of the diameter of the tree. The diameter of
a binary tree is the length of the longest path between any two nodes
in a tree. Note: The length of path between two nodes is represented
by the number of edges between them. This path may or may not pass
through the root.
Example :
Given a b i n a r y t r e e
1
/ \
2 3
/ \
0.1. BINARY TREE (40%) xi
4 5
0.1.3 Paths
In this section, we mainly solve path related problems. As we mentioned
in Chapter ??, there are three types of path depending on the starting and
ending node type of the path. We might be asked to get minimum/maxi-
mum/each path sum/ path length from these three cases: 1) root-to-leaf,
2) Root-to-Any node, 3) Any-node to-Any node.
Also, maximum or minimum questions is more difficult than the exact
path sum, because sometimes when there are negative values in the tree, it
makes the situation harder.
We normally have two ways to solve these problems. One is using DFS
traverse and use global variable and current path variable in the parameters
of the recursive function to track the path and collect the results.
The second way is DFS and Divide and Conquer, we treat each node as
a root tree, we return its result, and for a node, after we get result of left
and right subtree, we merge the result.
xii TREE QUESTIONS(10%)
0.6 112. Path Sum (Easy). Given a binary tree and a sum, determine
if the tree has a root-to-leaf path such that adding up all the values
along the path equals the given sum. Note: A leaf is a node with no
children.
Example :
Given t h e below b i n a r y t r e e and sum = 2 2 ,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
17 r e t u r n True
18 return False
0.7 129. Sum Root to Leaf Numbers (Medium). Given a binary tree
containing digits from 0-9 only, each root-to-leaf path could represent a
number. An example is the root-to-leaf path 1->2->3 which represents
the number 123. Find the total sum of all root-to-leaf numbers. Note:
A leaf is a node with no children.
Example :
I nput : [ 1 , 2 , 3 , 4 , 5 ]
1
/ \
2 3
/ \
4 5
Output : 262
Explanation :
The r o o t −to−l e a f path 1−>2−>4 r e p r e s e n t s t h e number 1 2 4 .
The r o o t −to−l e a f path 1−>2−>5 r e p r e s e n t s t h e number 1 2 5 .
The r o o t −to−l e a f path 1−>3 r e p r e s e n t s t h e number 1 3 .
T h e r e f o r e , sum = 124 + 125 + 13 = 2 6 2 .
0.8 437. Path Sum III You are given a binary tree in which each node
contains an integer value. Find the number of paths that sum to a
given value. The path does not need to start or end at the root or a
leaf, but it must go downwards (traveling only from parent nodes to
0.1. BINARY TREE (40%) xv
child nodes). The tree has no more than 1,000 nodes and the values
are in the range -1,000,000 to 1,000,000.
Example :
r o o t = [ 1 0 , 5 , − 3 , 3 , 2 , n u l l , 1 1 , 3 , − 2 , n u l l , 1 ] , sum = 8
10
/ \
5 −3
/ \ \
3 2 11
/ \ \
3 −2 1
1 . 5 −> 3
2 . 5 −> 2 −> 1
3 . −3 −> 11
However, to get the sum of any to any path (downwards), for each
node, we treat it as root node, and call rootToAny, to get satisfactary
total paths starts from current node, and we divide the remaining tasks
(starting from any other nodes to its left and right subtree). Thus the
time complexity if O(n2 ). n subproblems and each takes O(n) time.
1 ’ ’ ’ f i r s t r e c u r s i o n : we t r a v e r s e t h e t r e e and u s e any
node a s r o o t , and c a l l rootToAny t o g e t i t s p a t h s ’ ’ ’
2 d e f pathSum ( s e l f , r o o t , sum ) :
3 i f not r o o t :
4 return 0
5
6 r e t u r n s e l f . rootToAny ( r o o t , sum ) + s e l f . pathSum ( r o o t .
l e f t , sum ) + s e l f . pathSum ( r o o t . r i g h t , sum )
array: we need to set two pointers, one for subarray start and another
for the end. We can use prefix sum to decrease the time complexity
to O(n). The sum from n1 to n2 is P[n2]-P[n1] = sum, thus, we need
to check P[n1], which equals to P[n2]-sum at each node. To deal with
case: [0,0], sum = 0, we need to add 0:1 into the hashmap. Another
difference is: in the tree we are using DFS traversal, for a given node,
when we finish visit its left subtree and right subtree, and return to
its parent level, we need to reset the hashmap. So, this is DFS with
backtracking too.
1 d e f anyToAnyPreSum ( s e l f , r o o t , sum , c u r r , ans , preSum ) :
2 i f r o o t i s None :
3 return
4 # process
5 c u r r += r o o t . v a l
6 ans [ 0 ] += preSum [ c u r r −sum ]
7 preSum [ c u r r ] += 1
8 s e l f . anyToAnyPreSum ( r o o t . l e f t , sum , c u r r , ans , preSum )
9 s e l f . anyToAnyPreSum ( r o o t . r i g h t , sum , c u r r , ans , preSum )
10 preSum [ c u r r ] −= 1 #b a c k t r a c k t o c u r r e n t s t a t e
11 return
12
13 d e f pathSum ( s e l f , r o o t , sum ) :
14 i f not r o o t :
15 return 0
16 ans = [ 0 ]
17 preSum = c o l l e c t i o n s . d e f a u l t d i c t ( i n t )
18 preSum [ 0 ] = 1
19 s e l f . anyToAnyPreSum ( r o o t , sum , 0 , ans , preSum )
20 r e t u r n ans [ 0 ]
0.9 124. Binary Tree Maximum Path Sum (hard). Given a non-
empty binary tree, find the maximum path sum. For this problem,
a path is defined as any sequence of nodes from some starting node
to any node in the tree along the parent-child connections. The path
must contain at least one node and does not need to go through
the root.
Example 1 :
Input : [ 1 , 2 , 3 ]
1
/ \
2 3
Output : 6
Example 2 :
Input : [ − 1 0 , 9 , 2 0 , n u l l , n u l l , 1 5 , 7 ]
0.1. BINARY TREE (40%) xvii
−10
/ \
9 20
/ \
15 7
Output : 42
For example , g i v e n t h e f o l l o w i n g t r e e :
1
/ \
2 5
/ \ \
3 4 6
The f l a t t e n e d t r e e s h o u l d l o o k l i k e :
1
\
2
\
3
\
4
\
5
\
6
0.11 617. Merge Two Binary Trees. Given two binary trees and imag-
ine that when you put one of them to cover the other, some nodes of
the two trees are overlapped while the others are not.
You need to merge them into a new binary tree. The merge rule is
that if two nodes overlap, then sum node values up as the new value
of the merged node. Otherwise, the NOT null node will be used as
the node of new tree.
Example 1 :
Input :
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
Output :
Merged t r e e :
3
/ \
4 5
/ \ \
5 4 7
5 return t2
6 i f t 1 and t 2 i s None :
7 return t1
8 node = TreeNode ( t 1 . v a l+t 2 . v a l )
9 # d i v i d e and conquer , l e f t r e s u l t and t h e r i g h t r e s u l t
10 node . l e f t = s e l f . mergeTrees ( t 1 . l e f t , t 2 . l e f t )
11 node . r i g h t = s e l f . mergeTrees ( t 1 . r i g h t , t 2 . r i g h t )
12 r e t u r n node
I nput :
4
/ \
2 7
/ \ / \
1 3 6 9
Output :
4
/ \
7 2
/ \ / \
9 6 3 1
2. The left subtree is the maximum tree constructed from left part
subarray divided by the maximum number.
3. The right subtree is the maximum tree constructed from right
part subarray divided by the maximum number.
Construct the maximum tree by the given array and output the root
node of this tree.
Example 1 :
Input : [ 3 , 2 , 1 , 6 , 0 , 5 ]
Output : r e t u r n t h e t r e e r o o t node r e p r e s e n t i n g t h e
following tree :
6
/ \
3 5
\ /
2 0
\
1
Note :
The s i z e o f t h e g i v e n a r r a y w i l l be i n t h e r a n g e
[1 ,1000].
1. We scan numbers from left to right, build the tree one node by
one step;
2. We use a queue to keep some (not all) tree nodes and ensure a
decreasing order;
3. For each number, we keep popping the queue until empty or a big-
ger number appears; 1) The kicked out smaller number is current
node’s left child (temporarily, this relationship may change in the
future). 2) The bigger number (if exist, it will be still in stack) is
current number’s parent, this node is the bigger number’s right
child. Then we push current number into the stack.
1 d e f constructMaximumBinaryTree ( s e l f , nums ) :
2 """
3 : type nums : L i s t [ i n t ]
4 : r t y p e : TreeNode
5 """
6 i f not nums :
7 r e t u r n None
8 deQ = c o l l e c t i o n s . deque ( )
9 f o r i , v i n enumerate ( nums ) :
10 node = TreeNode ( v )
11 w h i l e deQ and deQ [ − 1 ] . v a l < v :
12 node . l e f t = deQ [ −1]
13 deQ . pop ( )
14 i f deQ :
15 deQ [ − 1 ] . r i g h t = node
16 deQ . append ( node )
17 r e t u r n deQ [ 0 ]
5
xxiv TREE QUESTIONS(10%)
/ \
1 5
/ \ \
5 5 5
Output : 4
Solution 1: DFS and Divide and Conquer. First, all the leaf
nodes are univalue subtree with count 1 and also it is the base case
with (True, leaf.val, 1) as return. If we are at node 1, we check the left
subtree and right subtree if they are univalue, and what is their value,
and what is there count. Or for cases that a node only has one subtree.
If the val of the subtree and the current node equals, we increase the
count by one, and return (True, node.val, l_count+r_count+1). All
the other cases, we only have (False, None, l_count+r_count).
1 def countUnivalSubtrees ( s e l f , root ) :
2 i f not r o o t :
3 return 0
4
5 def univalSubtree ( root ) :
6 i f r o o t . l e f t i s None and r o o t . r i g h t i s None :
7 r e t u r n ( True , r o o t . v a l , 1 )
8 l_uni , l_val , l_count = True , None , 0
9 i f root . l e f t :
10 l_uni , l_val , l_count = u n i v a l S u b t r e e ( r o o t . l e f t
)
11 r_uni , r_val , r_count = True , None , 0
12 i f root . right :
13 r_uni , r_val , r_count = u n i v a l S u b t r e e ( r o o t .
right )
14 i f l_uni and r_uni :
15 i f l _ v a l i s None o r r_val i s None :# a node with
o n l y one s u b t r e e
16 i f l _ v a l == r o o t . v a l o r r_val == r o o t . v a l :
17 r e t u r n ( True , r o o t . v a l , l_count+r_count
+1)
18 else :
19 r e t u r n ( F a l s e , None , l_count+r_count )
20 i f l _ v a l == r_val == r o o t . v a l : # a node with
both s u b t r e e s
21 r e t u r n ( True , r o o t . v a l , l_count+r_count +1)
22 else :
23 r e t u r n ( F a l s e , None , l_count+r_count )
24 r e t u r n ( F a l s e , None , l_count+r_count )
25
26 _, _, count = u n i v a l S u b t r e e ( r o o t )
27 r e t u r n count
I nput : r o o t = [ 3 , 5 , 1 , 6 , 2 , 0 , 8 , n u l l , n u l l , 7 , 4 ] , t a r g e t = 5 , K
= 2
3
/ \
5 1
/ \ | \
6 2 0 8
/ \
7 4
Output : [ 7 , 4 , 1 ]
Explanation :
The nodes t h a t a r e a d i s t a n c e 2 from t h e t a r g e t node ( with
value 5)
have v a l u e s 7 , 4 , and 1 .
Figure 1: Two Cases of K Distance Nodes marked in blue and red arrows.
16 nq . append ( n . l e f t )
17 i f n. right :
18 nq . append ( n . r i g h t )
19 q = nq
20 d += 1
21 r e t u r n ans
22
23 # g e t depth o f t a r g e t
24 d e f getDepth ( r o o t , t a r g e t , K, ans ) :
25 i f not r o o t :
26 r e t u r n −1
27 i f r o o t == t a r g e t :
28 return 0
29 # co nqu er
30 l e f t = getDepth ( r o o t . l e f t , t a r g e t , K, ans )
31 r i g h t = getDepth ( r o o t . r i g h t , t a r g e t , K, ans )
32 i f l e f t == −1 and r i g h t == −1:
33 r e t u r n −1
34 else :
35 dis = 0
36 i f l e f t != −1:
37 d i s = l e f t +1
38 i f root . right :
39 ans += g e t D i s t a n c e K ( r o o t . r i g h t , K−d i s
−1)
40 else :
41 dis = right + 1
42 i f root . l e f t :
43 ans += g e t D i s t a n c e K ( r o o t . l e f t , K−d i s −1)
44 i f d i s == K:
45 ans . append ( r o o t . v a l )
46 return dis
47
48 ans = g e t D i s t a n c e K ( t a r g e t , K)
49 getDepth ( r o o t , t a r g e t , K, ans )
50 r e t u r n ans
10 dfs ( root )
11 seen = set ( [ target ] )
12 q = [ target ]
13 d = 0
14 while q :
15 i f d == K:
16 r e t u r n [ node . v a l f o r node i n q ]
17 nq = [ ]
18 for n in q :
19 f o r n e i i n [ n . l e f t , n . r i g h t , n . par ] :
20 i f n e i and n e i not i n s e e n :
21 s e e n . add ( n e i )
22 nq . append ( n e i )
23 q = nq
24 d += 1
25 return [ ]
3. 426. Convert Binary Search Tree to Sorted Doubly Linked List (medium)
0.16 98. Validate Binary Search Tree (medium) Given a binary tree,
determine if it is a valid binary search tree (BST). Assume a BST is
defined as follows:
• The left subtree of a node contains only nodes with keys less than
the node’s key.
• The right subtree of a node contains only nodes with keys greater
than the node’s key.
• Both the left and right subtrees must also be binary search trees.
1 Example 1 :
2
3 Input :
4 2
5 / \
6 1 3
7 Output : t r u e
8
9 Example 2 :
10
11 5
12 / \
0.2. BINARY SEARCHING TREE (BST) xxix
13 1 4
14 / \
15 3 6
16 Output : f a l s e
17 E x p l a n a t i o n : The i n p u t i s : [ 5 , 1 , 4 , n u l l , n u l l , 3 , 6 ] . The r o o t
node ’ s v a l u e
18 i s 5 but i t s r i g h t c h i l d ’ s v a l u e i s 4 .
9 ans = i n O r d e r ( r o o t )
10 p r e = f l o a t ( "− i n f " )
11 f o r v i n ans :
12 i f v <= p r e :
13 return False
14 pre = v
15 r e t u r n True
Input : [ 1 , 3 , n u l l , n u l l , 2 ]
1
/
3
\
2
Output : [ 3 , 1 , n u l l , n u l l , 2 ]
3
/
1
\
2
Example 2 :
Input : [ 3 , 1 , 4 , n u l l , n u l l , 2 ]
3
/ \
1 4
/
2
Output : [ 2 , 1 , 4 , n u l l , n u l l , 3 ]
2
/ \
1 4
/
3
valid BST must have a sorted order. Therefore, we obtain the inorder
traversed list, and sort them by the node value, and compared the
sorted list and the unsorted list to find the swapped nodes.
1 def recoverTree ( s e l f , root ) :
2 """
3 : type r o o t : TreeNode
4 : r t y p e : v o i d Do not r e t u r n anything , modify r o o t in−
place instead .
5 """
6 def inorder ( root ) :
7 i f not r o o t :
8 return [ ]
9 return inorder ( root . l e f t ) + [ root ] + inorder ( root .
right )
10
11
12 ans = i n o r d e r ( r o o t )
13 s a n s = s o r t e d ( ans , key = lambda x : x . v a l )
14 # swap
15 f o r x , y i n z i p ( ans , s a n s ) :
16 i f x != y :
17 x . val , y . val = y . val , x . val
18 break
24 l e f t _ t a i l = left_head . l e f t
25 # c o n n e c t t a i l with c u r r e n t node
26 l e f t _ t a i l . r i g h t = curr_node
27 curr_node . l e f t = l e f t _ t a i l
28 # new_head p o i n t s t o l e f t _ h e a d
29 new_head = l e f t _ h e a d
30
31 i f right_head :
32 r i g h t _ t a i l = r i g h t _ h e ad . l e f t
33 # c o n n e c t head with c u r r e n t node
34 curr_node . r i g h t = r i g h t _ h e a d
35 r i g h t _ h e a d . l e f t = curr_node
36 n e w_ t a i l = r i g h t _ t a i l # n e w_ t a i l p o i n t s t o
right_tail
37
38 new_head . l e f t = n e w_ t a i l
39 n e w_ t a i l . r i g h t = new_head
40 r e t u r n new_head
0.2.2 Operations
In this section, we should problems related to operations we introduced
in section ??, which include SEARCH, INSERT, GENERATE, DELETE.
LeetCode Problems include:
Given t h e s o r t e d a r r a y : [ − 1 0 , − 3 , 0 , 5 , 9 ] ,
1 d e f sortedArrayToBST ( s e l f , nums ) :
2 """
3 : type nums : L i s t [ i n t ]
4 : r t y p e : TreeNode
5 """
6 d e f generatebalancedBST ( l , r ) :
7 i f l >r :
8 r e t u r n None
9 m = ( l+r ) //2
10 t r e e = TreeNode ( nums [m] )
11 t r e e . l e f t = generatebalancedBST ( l ,m−1)
12 t r e e . r i g h t = generatebalancedBST (m+1 , r )
13 return tree
14 r e t u r n generatebalancedBST ( 0 , l e n ( nums ) −1)
109. Convert Sorted List to Binary Search Tree, the difference is here
we have a linked list, we can convert the linked list into a list nums
Solution: When we read the signal, list all of it, we need to use for
loop, to pose each element as root, and the left side is left tree, the
right side is used for the right tree. Use DPS: We generated all the
BST that use ith node as root
1 d e f numTrees ( s e l f , n ) :
2 """
3 : type n : i n t
4 : rtype : int
5 """
6 d e f c o n s t r u c t A l l B S T ( s t a r t , end ) :
7 i f s t a r t >end :
8 r e t u r n [ None ]
9
10 #go through t h e s t a r t t o end , and u s e t h e i t h
as root
11 r s l t =[]
12 leftsubs , rightsubs =[] ,[]
13 f o r i i n xrange ( s t a r t , end+1) :
14
15 l e f t s u b s=c o n s t r u c t A l l B S T ( s t a r t , i −1)
16 r i g h t s u b s=c o n s t r u c t A l l B S T ( i +1 , end )
xxxvi TREE QUESTIONS(10%)
17 for leftnode in l e f t s u b s :
18 for rightnode in rightsubs :
19 node = TreeNode ( i )
20 node . l e f t =l e f t n o d e
21 node . r i g h t=r i g h t n o d e
22 r s l t . append ( node )
23 return r s l t
24
25 r s l t= constructAllBST (1 , n)
26 return len ( r s l t )
27
However, it still cant pass the test, try the bottom up iterative so-
lution with memorization: T (start, end) = T (start, i − 1) ∗ T (i +
1, end)T (j, i) = T (j, i − 1) ∗ T (i + 1, i). How to explain this?
1 d e f numTrees1 ( s e l f , n ) :
2 r e s = [ 0 ] ∗ ( n+1)
3 res [ 0 ] = 1
4 f o r i i n xrange ( 1 , n+1) : #when i =2 , j = [ 0 , 1 ] r e s [ 2 ] =
r e s [ 0 ] ∗ r e s [2 −1 −0] + r e s [ 1 ] ∗ r e s [2 −1 −1]
5 f o r j i n xrange ( i ) : #i [ 1 , n ] , j =[0 , i ) , t h e c a s e i f
f o r one node ,
6 r e s [ i ] += r e s [ j ] ∗ r e s [ i −1−j ]
7 return res [ n ]
Using math:
0.2. BINARY SEARCHING TREE (BST) xxxvii
6. 426. Convert Binary Search Tree to Sorted Doubly Linked List (find
the precessor and successor)
16 r e t u r n LCA( node . r i g h t )
17 r e t u r n node
18
19 r e t u r n LCA( r o o t )
24 s t a c k . append ( r i g h t )
25 r i g h t=r i g h t . l e f t #keep g e t t i n g t h e s u c c e s s o r
5 \
6 2
7 /
8 1
9
10 L = 1
11 R = 3
12
13 Output :
14 3
15 /
16 2
17 /
18 1
19
A mutant of this is to split the BST into two, one is smaller or equal to the
given value, the other is bigger.
0.3 Exercise
0.3.1 Depth
104. Maximum Depth of Binary Tree (Easy)
Given a binary tree, find its maximum depth. The maximum depth is
the number of nodes along the longest path from the root node down to the
farthest leaf node.
Note: A leaf is a node with no children.
1 Example :
2
3 Given b i n a r y t r e e [ 3 , 9 , 2 0 , n u l l , n u l l , 1 5 , 7 ] ,
4
5 3
6 / \
7 9 20
8 / \
9 15 7
10
11 r e t u r n i t s depth = 3 .
14 for c in children :
15 if c:
16 depth = max( depth , s e l f . maxDepth ( c ) )
17 r e t u r n depth+1
0.3.2 Path
113. Path Sum II (medium). Given a binary tree and a sum, find all
root-to-leaf paths where each path’s sum equals the given sum. Note: A leaf
is a node with no children.
Example :
Given t h e below b i n a r y t r e e and sum = 2 2 ,
5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
Return :
[
[5 ,4 ,11 ,2] ,
[5 ,8 ,4 ,5]
]
Root to Leaf. Becareful that we only collect result at the leaf, and for the
right tree and left tree we need to make sure it is not None:
1 def binaryTreePaths ( s e l f , root ) :
2 """
3 : type r o o t : TreeNode
4 : rtype : List [ s t r ]
5 """
6 d e f d f s ( r o o t , c u r r , ans ) :
7 i f r o o t . l e f t i s None and r o o t . r i g h t i s None : # a l e a f
8 ans . append ( c u r r+s t r ( r o o t . v a l ) )
9 return
10 i f root . l e f t :
11 d f s ( r o o t . l e f t , c u r r+s t r ( r o o t . v a l )+ ’−> ’ , ans )
12 i f root . right :
13 d f s ( r o o t . r i g h t , c u r r+s t r ( r o o t . v a l )+ ’−> ’ , ans )
14 i f r o o t i s None :
15 return [ ]
16 ans = [ ]
17 d f s ( r o o t , ’ ’ , ans )
18 r e t u r n ans
Root to Any with Global Variable to track the any to any through
root.
1 def diameterOfBinaryTree ( s e l f , root ) :
2 """
3 : type r o o t : TreeNode
4 : rtype : int
5 """
6 # t h i s i s t h e l o n g e s t path from any t o any
7
8 d e f rootToAny ( r o o t , ans ) :
9 i f not r o o t :
10 return 0
11 l e f t = rootToAny ( r o o t . l e f t , ans )
12 r i g h t = rootToAny ( r o o t . r i g h t , ans )
13 ans [ 0 ] = max( ans [ 0 ] , l e f t +r i g h t ) # t r a c k t h e any t o any
through r o o t
14 r e t u r n max( l e f t , r i g h t ) + 1 #g e t t h e maximum depth o f
r o o t t o any
15 ans = [ 0 ]
16 rootToAny ( r o o t , ans )
17 r e t u r n ans [ 0 ]