Chapter 16 Tree Traversal

Note: Traversal(\(O(N)\)) is different from search(\(O(LogN)\)).

In/Pre/Post-Order Traversal are all of DFS algorithm.

16.1 Morris Traversal

Morris只提供了中序遍历的方法,在中序遍历的基础上稍加修改可以实现前序,而后续就要再费点心思了.这篇文章把三种方法都列出来了: http://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html

16.1.1 Morris Traversal InOrder (Two pointers)

The Morris is the M in KMP algo.

Version 1: Tree is modified.

这个函数的结果把所有的节点用right node关系从大到小链接起来了!!!其实就是等同于下面这个面试题:

  1. flatten bst成为linkedlist,要求最后的linkedlist必须是sorted而且不能占用额外的空间.

http://bit.ly/2wZ71Xx

Version 2: Tree is restored.

在恢复树的时候visit节点.

Version 2’s while condition is more complex, when backtrackig, c is set to c->right, else c is set to c->left to move forward.

https://en.wikipedia.org/wiki/Threaded_binary_tree#The_array_of_Inorder_traversal

http://blog.csdn.net/zone_programming/article/details/50573840

http://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html

16.2 94. Binary Tree Inorder Traversal

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

For example: Given binary tree [1,null,2,3],

   1
    \
     2
    /
   3

return [1,3,2]

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

https://leetcode.com/problems/binary-tree-inorder-traversal/

很详细的解释: http://bit.ly/2vMxedv

16.2.1 Algo 0:

Recursion

16.2.2 Algo 1: Iterative Traversal with Linear Space O(N)

模板是7 Line Iterative Inorder Traversal Code with stack:

void inorderTraversal(TreeNode* c) {
stack<TreeNode> stk;
while (c or !stk.empty()) {
while(c) stk.push(c), c = c->left;// push all leftish nodes into stack c = stk.top(), stk.pop(), /
visit(c)*/ c = c->right;// peek at top of stack } // at this point, c==0 and stack is empty, which means our work is done }

上题的iterative解法的代码如下:

16.3 783. Minimum Distance Between BST Nodes

Given a Binary Search Tree (BST) with the root node root, return the minimum difference between the values of any two different nodes in the tree.

Example :

Input: root = [4,2,6,1,3,null,null]
Output: 1
Explanation:
Note that root is a TreeNode object, not an array.

The given tree [4,2,6,1,3,null,null] is represented by the following diagram:

          4
        /   \
      2      6
     / \    
    1   3  

while the minimum difference in this tree is 1, it occurs between node 1 and node 2, also between node 3 and node 2.

https://leetcode.com/problems/minimum-distance-between-bst-nodes/

16.6 285. Inorder Successor in BST

Given a binary search tree and a node in it, find the in-order successor of that node in the BST.

Note: If the given node has no in-order successor in the tree, return null.

https://leetcode.com/problems/inorder-successor-in-bst/

CLRS P292

http://www.geeksforgeeks.org/inorder-successor-in-binary-search-tree/

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

找继承.CLRS上面的例子就是有父节点的情况.但是这道题是没有父节点.

有父节点:

Case 1:

Case 2:

无父节点:

http://algorithms.tutorialhorizon.com/inorder-successor-in-binary-search-tree-without-using-parent-link/

这个是我看到最简洁的写法:

上面写法虽然简洁,却不是最高效的.虽然复杂度都是\(O(H)\),下面这个应该高效一些:

16.8 272. Closest Binary Search Tree Value II

Given a non-empty binary search tree and a target value, find k values in the BST that are closest to the target.

Note:

Given target value is a floating point.

You may assume k is always valid, that is: k ≤ total nodes.

You are guaranteed to have only one unique set of k values in the BST that are closest to the target.

Follow up:

Assume that the BST is balanced, could you solve it in less than \(O(n)\) runtime (where n = total nodes)?

Hint:

Consider implement these two helper functions:

getPredecessor(N), which returns the next smaller node to N.

getSuccessor(N), which returns the next larger node to N.

https://leetcode.com/problems/closest-binary-search-tree-value-ii/

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

true || blah …. blah 如果第一个是true ||, 会把后面所有的短路掉,不管有多少||或者&&.


16.10 255. Verify Preorder Sequence in Binary Search Tree

https://leetcode.com/problems/verify-preorder-sequence-in-binary-search-tree/


16.17 538. Convert BST to Greater Tree

https://leetcode.com/problems/convert-bst-to-greater-tree

Input: The root of a Binary Search Tree like this:
              5
            /   \
           2     13

Output: The root of a Greater Tree like this:
             18
            /   \
          20     13

这道题只要从大往小遍历BST就可以了,也就是DFS先右后左,记录已经遍历过的节点的值的和,每遍历到一个新节点就把节点值加上这个和.It is Reverse-Inorder Traversal.

16.18 536. Construct Binary Tree from String

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

Input: "4(2(3)(1))(6(5))"
Output: return the tree root node representing the following tree:

       4
     /   \
    2     6
   / \   / 
  3   1 5   

对于例题中的“4(2(3)(1))(6(5))”,可知4是根节点,“2(3)(1)”是左子树,“6(5)”是右子树.可以想到应该用递归的方式建树. 这里怎么判断它的左子树的开始和结尾呢? 通过对“()”进行计数,当遇到’(‘加1,遇到’)’减去1.当为0时,说明括号是完全匹配的,此时它自己可以形成一个新树.剩下的就是加括号的右子树的字符串.

参考: string.html#nested-string

DFS遍历的Parenthesis structure. CLRS P606.

16.19 508. Most Frequent Subtree Sum

https://leetcode.com/problems/most-frequent-subtree-sum

Given the root of a tree, you are asked to find the most frequent subtree sum. 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). So what is the most frequent subtree sum value? If there is a tie, return all the values with the highest frequency in any order.

Examples 1

Input:

  5
 /  \
2   -3

return [2, -3, 4], since all the values happen only once, return all of them in any order.

Examples 2

Input:

  5
 /  \
2   -5

return [2], since 2 happens twice, however -5 only occur once.

Note: You may assume the sum of values in any subtree is in the range of 32-bit signed integer.

16.20 Convert a Binary Tree to Threaded binary tree

http://www.geeksforgeeks.org/convert-binary-tree-threaded-binary-tree-set-2-efficient/

Idea of Threaded Binary Tree is to make inorder traversal faster and do it without stack and without recursion. In a simple threaded binary tree, the NULL right pointers are used to store inorder successor. Where-ever a right pointer is NULL, it is used to store inorder successor.

上图中1,5,7,9叫做threaded node.

16.22 314. Binary Tree Vertical Order Traversal

Given a binary tree, return the vertical order traversal of its nodes’ values. (ie, from top to bottom, column by column).

If two nodes are in the same row and column, the order should be from left to right.

Examples:

Given binary tree [3,9,20,null,null,15,7],

   3
  /\
 /  \
 9  20
    /\
   /  \
  15   7

return its vertical order traversal as: [ [9], [3,15], [20], [7] ]

Given binary tree [3,9,8,4,0,1,7],

     3
    /\
   /  \
   9   8
  /\  /\
 /  \/  \
 4  01   7

return its vertical order traversal as: [ [4], [9], [3,0,1], [8], [7] ]

Given binary tree [3,9,8,4,0,1,7,null,null,null,2,5] (0’s right child is 2 and 1’s left child is 5),

     3
    /\
   /  \
   9   8
  /\  /\
 /  \/  \
 4  01   7
    /\
   /  \
   5   2

return its vertical order traversal as: [ [4], [9,5], [3,0,1], [8,2], [7] ]

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

解题的第一步是求出左右两边相对于root的长度,DFS和BFS都可以搞定其实; 第二步是通过index把数值填到相应的坑里面.

一上来没看清楚题意,用了two DFS的解法.

结果得到一个error:

才发现题目要求结果中的node要from top to bottom. 转念一想,BFS也是没有问题的. 代码如下:

这里第一步得到ml和mr所用的DFS用BFS也可以得到. 如果把题目要求改为from left to right,就是上面的“错误”的那个算法.

16.23 652. Find Duplicate Subtrees

Given a binary tree, return all duplicate subtrees. For each kind of duplicate subtrees, you only need to return the root node of any one of them.

Two trees are duplicate if they have the same structure with same node values.

Example 1:

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

The following are three duplicate subtrees:

      2
     /
    4
   /
  5

and

    4
   /
  5

and

  5

Therefore, you need to return above trees’ root in the form of a list/vector.

https://leetcode.com/problems/find-duplicate-subtrees

上面提到有3颗duplicate trees:[2,4,5],[4,5]和[5], [2,4,5]和[4,5]有两个duplicates,但是[5]有3个duplicates. 要求我们返回节点[2,4,5]

subtree的问题一般两个办法,一个是用is_same_tree来检测, 一个是用preorder string,通常后一个效果比较好. 这道题前一个方法我做了超时了.用后一个方法就极其简单.

Use preorder with delimiter represents a unique binary tree. 用DFS traversal, 当我们走到一个node的时候,要它的preorder string,然后放到map里面看是否曾经有过这样的preorder string,如果刚好有一个就加入final result; 而且不管有没有都increase counter by 1, 以防止重复加入.

这道题的string用preorder, postorder都可以,但是inorder要注意一下,对每层stackframe计算完之后要加一个标记.和subtree-of-another-tree的第二个解法类似.

我在用g++调试时发现第10行子表达式的计算顺序是从右到左,这在C++标准里面是没有规定的. 同样道理的有函数参数的入栈顺序.

如果用inorder traversal with delimiter,上图的两个边框里面的subtree都是“x,0,x,0,x”,所以必须在尾部加一个标记.

这个性质其实在Serialize and Deserialize Binary Tree里面已经使用过了.