Premiumlab  

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

 

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:

 

  1. 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]
    ]
    
  2. 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]
    ]
    
  3. 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]
    ]
    

 

 

Sol:
 
Pretty much like Tree Level Order Print. 
 
Create a list s to store the node and index/column of this node in the final output in the format of (index, col).
 
Use a dictionary to get the pop pair from s.  The key is col/index, and the value is the value of the node. 
 
If the left node exists, append the (left node, col - 1) to the list s. It is col - 1 because the left node shows in the previous index of the return list. 
 
Likewise, if the right node exists, append the (right node, col + 1) to list s. It is col + 1 because the right node shows in the next index of the return list.
 
In the end, return the value of the dictionary in the ascending way of keys.
 
P.S. We use a list to store the (node, col) tuple. The pop the node and col from the tuple to the dictionary. The reasons why we still need the dictionary are 1) we need to return the value of node, not the node itself. Thus the value of the dictionary is node.val.  2) We will output node values in the ascdending order of cols. Thus, the key of the dictionary is the col. 
 
To sum it up, the list is actually doing the heavy lifting.  
 
# Definition for a binary tree node.
class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

from collections import defaultdict

class Solution(object):
    def verticalOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
    
    
        cols = defaultdict(list)
        s = list()
        if root:
            # elements in s have the format of (node, index), where index shows the index/column if this node in the final output list.
            s.append((root, 0))
            while s:
                node, col = s.pop(0)
                # for cols dictionary, the key is col/index; the value is node.val
                cols[col].append(node.val)
                # the left subnode is on the left side of the tree, and according to the output format, it is at the previous index.
                if node.left:
                    s.append((node.left, col - 1))
                # the right subnode is on the right side of the tree, and according to the output format, it is at the next index.        
                if node.right:
                    s.append((node.right, col + 1))
        # return a list. 
        return [cols[k] for k in sorted(cols.keys())]
 

 

 
Note:
 
1 from collections import defaultdict 
should be written before the class Solution(object) line, otherwise it will raise error
 
2 The usage of defaultdict is different from a dictionary. 
 
When you get a nonexistent key from a dictionary, it wiill throw a KeyError whereas as for defaultdict, instead of throwing a KeyError, it will create  this item. 
 
Usually, a Python dictionary throws a KeyError if you try to get an item with a key that is not currently in the dictionary. The defaultdict in contrast will simply create any items that you try to access (provided of course they do not exist yet). To create such a "default" item, it calls the function object that you pass in the constructor (more precisely, it's an arbitrary "callable" object, which includes function and type objects). For the first example, default items are created using int(), which will return the integer object 0. For the second example, default items are created using list(), which returns a new empty list object.
 
 
 
 
3 A pythonic way to traverse a dictionary. 
 
>>> x = [chr(i) for in range(9797 + 26)]
>>> x
['a''b''c''d''e''f''g''h''i''j''k''l''m''n''o''p''q''r''s''t''u''v''w''x''y''z']
 
 
>>> for i, v in enumerate(x):
    print("{} {}".format(i, v))
     
0 a
1 b
2 c
3 d
4 e
5 f
6 g
7 h
8 i
9 j
10 k
11 l
12 m
13 n
14 o
15 p
16 q
17 r
18 s
19 t
20 u
21 v
22 w
23 x
24 y
25 z
 
 # for i, v in enumerate(x)
# "enumerate"  assigns the index of x to i, and the value of x to v 
 
 
 
Similar problem:
 
 

Tree Level Order Print - SOLUTION

Given a binary tree of integers, print it in level order. The output will contain space between the numbers in the same level, and new line between different levels. For example, if the tree is:


title


The output should be:

1 
2 3 
4 5 6
 

Solution

It won’t be practical to solve this problem using recursion, because recursion is similar to depth first search, but what we need here is breadth first search. So we will use a queue as we did previously in breadth first search. First, we’ll push the root node into the queue. Then we start a while loop with the condition queue not being empty. Then, at each iteration we pop a node from the beginning of the queue and push its children to the end of the queue. Once we pop a node we print its value and space.

To print the new line in correct place we should count the number of nodes at each level. We will have 2 counts, namely current level count and next level count. Current level count indicates how many nodes should be printed at this level before printing a new line. We decrement it every time we pop an element from the queue and print it. Once the current level count reaches zero we print a new line. Next level count contains the number of nodes in the next level, which will become the current level count after printing a new line. We count the number of nodes in the next level by counting the number of children of the nodes in the current level. Understanding the code is easier than its explanation:

 

 

 

class Node:
    def __init__(self, val=None):
        self.left = None
        self.right = None
        self.val =  val

 

 
 
 
 
def levelOrderPrint(tree):
    if not tree:
        return
    nodes=collections.deque([tree])
    currentCount, nextCount = 1, 0
    while len(nodes)!=0:
        currentNode=nodes.popleft()
        currentCount-=1
        print currentNode.val,
        if currentNode.left:
            nodes.append(currentNode.left)
            nextCount+=1
        if currentNode.right:
            nodes.append(currentNode.right)
            nextCount+=1
        if currentCount==0:
            #finished printing current level
            print '\n',
            currentCount, nextCount = nextCount, currentCount

 

 

The time complexity of this solution is O(N), which is the number of nodes in the tree, so it’s optimal. Because we should visit each node at least once. The space complexity depends on maximum size of the queue at any point, which is the most number of nodes at one level. The worst case occurs when the tree is a complete binary tree, which means each level is completely filled with maximum number of nodes possible. In this case, the most number of nodes appear at the last level, which is (N+1)/2 where N is the total number of nodes. So the space complexity is also O(N). Which is also optimal while using a queue.

Again, this is a very common tree interview question!

 

Good Job!

posted on 2017-06-19 20:09  Premiumlab  阅读(134)  评论(0编辑  收藏  举报