Chapter 14 Binary Tree

Tree <=> Graph which is connected and no cycle(acyclic) and directed.

14.1 Basics of Tree Depth, Height and Level

节点分为5类: empty node, leaf node, half node(left missing, right missing), full/inner node.

  • Given a binary tree, how do you remove all the half nodes?

http://www.geeksforgeeks.org/given-a-binary-tree-how-do-you-remove-all-the-half-nodes/

根据CLRS的定义,一个点的高度height是该点到叶节点的Edge(边)的个数,深度depth是根节点到该点之间的edge的个数.

其实这些定义都是很灵活的,便于人们交流而已. Leetcode的题目种就不是这样定义的, Leetcode是看Node的个数(包括自身).

14.3 606. Construct String from Binary Tree

You need to construct a string consists of parenthesis and integers from a binary tree with the preorder traversing way. The null node needs to be represented by empty parenthesis pair “()”. And you need to omit all the empty parenthesis pairs that don’t affect the one-to-one mapping relationship between the string and the original binary tree.

Example 1:

Input: Binary tree: [1,2,3,4]
       1
     /   \
    2     3
   /    
  4     
Output: "1(2(4))(3)"

Explanation: Originallay it needs to be “1(2(4)())(3()())”, but you need to omit all the unnecessary empty parenthesis pairs. And it will be “1(2(4))(3)”.

Example 2:

Input: Binary tree: [1,2,3,null,4]
       1
     /   \
    2     3
     \  
      4 
Output: "1(2()(4))(3)"

Explanation: Almost the same as the first example, except we can’t omit the first parenthesis pair to break the one-to-one mapping relationship between the input and the output.

https://leetcode.com/problems/construct-string-from-binary-tree

如果不要求节约那个(),程序应该这样写:

如果要求节约右边的(),加一个条件就行了:

14.7 440. K-th Smallest in Lexicographical Order

Given integers n and k, find the lexicographically k-th smallest integer in the range from 1 to n.

Note: 1 <= k <= n <= 109.

Example:

Input: n: 13 k: 2
Output: 10

Explanation:
The lexicographical order is [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9], so the second smallest number is 10.

https://leetcode.com/problems/k-th-smallest-in-lexicographical-order

http://massivealgorithms.blogspot.com/2016/10/leetcode-440-k-th-smallest-in.html

https://github.com/shadowwalker2718/data_structure_algorithm/blob/master/leetcode_c/K-th%20Smallest%20in%20Lexicographical%20Order.h#L20

calsteps function: how to calculate the steps between curr and curr + 1?

Here we come up an idea to calculate by level.

Let head = curr, tail = curr + 1.

tail is always the next right node beside head's right most node (who shares the same ancestor "curr")

(2 is right next to 1, 20 is right next to 19, 200 is right next to 199).

so, if tail <= n, which means head’s right most node exists, we can simply add the number of nodes from head to tail to steps.

else if tail > n, which means n(the boundary node) is on the path between head to tail, add (n + 1 - head) to steps.

14.8 111. Minimum Depth of Binary Tree

Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.

https://leetcode.com/problems/minimum-depth-of-binary-tree/

  • BFS

BFS has a built-in feature, which is to find the shortest path. This makes BFS the best algorithm for this problem.

  • DFS

We can still use DFS but we have to full-scan the tree and use function \(min(\cdot)\) to find the mindepth.
Note: the base case in \(dfs(\cdot)\) is \(leaf node\).

  • Recursion

14.10 366. Find Leaves of Binary Tree

Given a binary tree, collect a tree’s nodes as if you were doing this: Collect and remove all leaves, repeat until the tree is empty.

Example: Given binary tree

          1
         / \
        2   3
       / \     
      4   5    

Returns [4, 5, 3], [2], [1].

Explanation:
1. Removing the leaves [4, 5, 3] would result in this tree:

          1
         / 
        2          
  1. Now removing the leaf [2] would result in this tree:
          1          
  1. Now removing the leaf [1] would result in the empty tree:
          []         

Returns [4, 5, 3], [2], [1].

https://leetcode.com/problems/find-leaves-of-binary-tree/

http://www.cnblogs.com/grandyang/p/5616158.html

这个题本质是求每个节点的max height. 很有代表性: 节点的高度height是在递归函数rec回溯的时候确定!!!

节点在vector的index就等于节点的max height.

int dep = max(rec(r,n->left), rec(r,n->right)) + 1;很关键.

这里不是用的DFS,是递归.

上面那个rec返回的是CLRS定义的高度height(叶子节点高度为0). 其实这样也行,不过返回的是高度+1:

14.11 364. Nested List Weight Sum II

https://leetcode.com/problems/nested-list-weight-sum-ii/

这个题给上面那道相似但不同.

节点的深度depth是在DFS前进的时候确定!!!所以这个难度要小点.可以直接把depth作为一个参数传到\(dfs()\).

NestedInteger是一个特别的int,可以是int,也可以是一个int的数组.

这道题的深度depth其实和上图的高度height相近但是又不完全相同.如果从树的角度来看,好比以最深那点为基准,所以没有任何冲突.不像树height的传统定义,没有固定的基准,任何叶子节点都可能是基准,这样会有冲突,造成max height或者min height的不同.

14.12 Binary Tree Upside Down

https://leetcode.com/problems/binary-tree-upside-down/

这题有一个重要的限制就是,整个数的任何一个右孩子都不会再生枝节,基本就是一个梳子的形状.

Right child node is a leaf or NULL, so it is not a problem. The crux is the left child node. We can imagine it as a subtree. We will return the root of the subtree as new root, and we also need the right most child as a connecting point to the original root(R) and original right child(R->right).

The tree is like a binary family tree, where left child is older brother and right child is younger brother. Whenever there is a younger brother, there must be a older brother. (You can definitely replace brother with sister.)

这题迭代的解法:

参考: http://blog.csdn.net/whuwangyi/article/details/43186045

14.13 Flatten Binary Tree to Linked List

Given a binary tree, flatten it to a linked list in-place.

For example, Given

         1
        / \
       2   5
      / \   \
     3   4   6

The flattened tree should look like:

   1
    \
     2
      \
       3
        \
         4
          \
           5
            \
             6

https://leetcode.com/problems/flatten-binary-tree-to-linked-list/

http://bit.ly/2wZ2W5O

两道leetcode原题
1. 判断一个array of integer是不是单调
2. flatten bst成为linkedlist,要求最后的linkedlist必须是sorted而且不能占用额外的空间.

http://bit.ly/2wZ71Xx

14.14 Symmetric Tree

https://leetcode.com/problems/symmetric-tree/

下面这个是我自己写的代码.先找思路,首先iterative很难做,因为是按照对称路径在比较. 考虑recursive的方法.这个镜像树是只关于Root对称,不是任意节点对称.所以recursive function要接受两个参数.

对root判断的logic其实可以包含在下面的recursive function里面,所以可以把代码稍微改短一行

      1
     / \
    2   2
   / \ / \
  3  4 4  3

      |
      V

    1   1
   /     \
  2       2
 / \     / \
3  4     4  3

方法就是: 左左右右….左孩子往左边走,右孩子往右边走….

14.15 Binary Tree Zigzag Level Order Traversal(BFS)

https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/

  • Algo 1: Two stacks

A trap here is donot forget switching the order of pushing left and right child!!!

因为容器是stack, push的时候加点和pop的时候加点正好相反.

  • Algo 2: deque or list

一个数据结构应该就够了.但是不能用queue,必须用dequeue或者list.

从前面pop的话,push就必须从后面.(不然变成了stack.) 这里layer的alternate可以用-1 times itself, or a^b=c trick.

14.17 297. Serialize and Deserialize Binary Tree

The tricky part is deserialize(*) function.

  1. DFS

Preorder with delimiter (Recursive)

https://leetcode.com/problems/serialize-and-deserialize-binary-tree/

http://fisherlei.blogspot.com/2013/03/interview-serialize-and-de-serialize.html

序列化的时候首先要考虑反序列化的时候怎么恢复.反序列化最好是从根开始生成树.所以要找一个算法很容易把根找出来.如果把Tree看成graph的话,BFS,DFS都可以满足条件.Tree traversal的preorder是一种DFS. Inorder和postorder既不是BFS也不是DFS.(这样看来preorder还蛮特别的算是树和图知识点的交集.)

在对树进行DFS的同时把节点值放入一个string实现序列化.反序列的时候,输入其实是一个dfs路径,就沿着路走并恢复节点.

Complexity: \(O(N)\)

Preorder with special delimeter can define a uniqe binary tree!!

用string function:

用istringstream:

优化:

上面的方法容易实现但不是最优的.二叉树的叶子节点数比内部节点数多一个.所以上图6个cell用了7个null.
优化的方法是把包围叶子节点的连续的null,null用一个token(比如$)表示.单独的null保持原样.这样原树有几个叶节点就节约几个token.

这个DFS函数有返回值,类似binary tree剥叶子问题返回树的深度.这种有返回值DFS函数的写法都是:
1. 终止条件/base case
2. 先call自己得到返回值,利用返回值构建本层函数的logic

And the delimeter between leaf node and $ can be removed:

  1. BFS

Layer by Layer (Iterative)
http://blog.csdn.net/ljiabin/article/details/49474445

2017(7-9月) 码农类 博士 全职 Facebook - 内推 - 技术电面 |Otherfresh grad应届毕业生
1. LC297 serialize/deserialize BST与原题不一样的是输出是vector,not a string.
2. LC133 Clone Graph与原题不一样的是输入不是一个Node, 而是vector<Node>, 需要clone这个vector里的所有nodes.问面试官所有的nodes是否fully connected他说什么情况都有可能.
http://bit.ly/2vOAjHw

Follow-up

  1. How to test?
    http://www.geeksforgeeks.org/serialize-deserialize-binary-tree/

  2. N-ary Tree/Trie/(sparse/dense) Graph
    http://www.geeksforgeeks.org/serialize-deserialize-n-ary-tree/

In an N-ary tree, there are no designated left and right children. An N-ary tree is represented by storing an array or list of child pointers with every node. The idea is to store an ‘end of children’ marker with every node. The following diagram shows serialization where ‘)’ is used as end of children marker. The diagram is taken from here.

  1. Do it using parenthesis property of DFS
    http://www.jiuzhang.com/solutions/binary-tree-serialization/

  2. Inorder + Postorder/Preorder
    用下面两道题的思路也可以解该题,但是肯定不是最优,因为需要双倍的空间.

Why in-order doesn’t work?
You CANNOT find root with in-order.

14.17.2 106. Construct Binary Tree from Postorder and Inorder Traversal

Given inorder and postorder traversal of a tree, construct the binary tree. Note: You may assume that duplicates do not exist in the tree.

https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/

Follow up 2:

  • If you are given two traversal sequences, can you construct the binary tree?

It depends on what traversals are given. If one of the traversal methods is Inorder then the tree can be constructed, otherwise not.

Therefore, following combination can uniquely identify a tree.

  • Inorder and Preorder.

  • Inorder and Postorder.

  • Inorder and Level-order.

And following do not:

Postorder and Preorder.

Preorder and Level-order.

Postorder and Level-order.


For example, Preorder, Level-order and Postorder traversals are same for the trees given in above diagram.
Preorder Traversal = AB
Postorder Traversal = BA
Level-Order Traversal = AB
So, even if three of them (Pre, Post and Level) are given, the tree can NOT be constructed!!

对BST来说,因为bst的性质,相当于Inorder已经给你了,所以只要知道另外一个就可以重建.

Follow up 3:

证明: why is one traversal not enough for a general tree, (without the information it is a BST)?

Answer: Let’s assume we have n distinct elements. There are \(n!\) possible lists to these n elements, however - the possible number of trees is much larger (\(2*n!\) possible trees for the n elements are all decayed trees, such that node.right=null in every node, thus the tree is actually a list to the right. There are \(n!\) such trees, and another \(n!\) trees where always node.left=null ). Thus, from pigeon hole principle - there is at least one list that generates 2 trees, thus we cannot reconstruct the tree from a single traversal. (QED)

Follow up 4:

  • How many different Binary Tree Possible given Preorder Sequence length N?
  • How many different BST Possible given N different values elements?

http://stackoverflow.com/questions/16004723/number-of-binary-search-trees-over-n-distinct-elements

Catalan增长的速度接近\(4^n/n^{3/2}\),当n大于5,catalan数大于\(2^n\).

\(Factorial > Catalan > 2^n\)