[LeetCode#102]Binary Tree Level Order Traversal

The problem:

Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).

For example:
Given binary tree {3,9,20,#,#,15,7},

    3
   / 
  9  20
    /  
   15   7

return its level order traversal as:

[
  [3],
  [9,20],
  [15,7]
]

My analysis:

This problem is easy and evident. The key idea follows the steps:
1. enqueue the initial root in the queue.
2.(in a while loop) 
    2.1 we dequeue a node from the queue
    2.2 add the node into the final answer set 
    2.3 add the node's left child and right child (if not null) into the queue
Note: for each new layer, we need to new a ArrayList<Integer>. 

The big concern here is we need to distingusih the node's layers, thus add them into different ArrayList<Integer>. There are two ways to solve this problem.
1. a direct way. using a hashmap to store each node's level.
    1.1 once we add a node's left child or right child into the queue, we also add the node's left and right children with the value of current.val + 1 into the hashmap.
    drawbacks: 
    1.1 since we use hashmap, we need extra cost in maintaining a hashmap. which would add the chance of writing a buggy codes. 
    1.2 we would never know if the current node is the final node of current level, before the get its next node(in queue), thus we have to delay the addition of the item at the next iteration. This kind of invariant could lead to a very ugly coding style, since we need to tackle the final layer outside the loop.
    

2. since the adjacent nodes(in queue) are also adjacency in level (in the same level or two adjacent levels). we could use two counter to record if current layer's nodes have been traversaled, if we just enter into a new layer. 
2.1 cur_num: record the nodes remained in the current level.
    iff cur_num == 0, the next node in the queue is a new layer.

if (cur_num == 0) { 
    ret.add(item);
    cur_num = next_num;
    next_num = 0;
    item = new ArrayList<Integer> ();
}


2.2 next_num: when we working on the current layer, we counter each left or right child into the next layer's number. 
if (cur_node.left != null) {
    next_num ++;
    queue.offer(cur_node.left);
}
            
if (cur_node.right != null) {
    next_num ++;
    queue.offer(cur_node.right);
}

A little skill in designing invariant. Usually there are two kinds of way in adding answer into final set.
1. delay the addition of the current layer's result at next layer.
while (queue.size() != 0) { //this way is so ugly and complex
....
    if (cur_level != pre_level) {
        if (cur_level > 0) { //if not the first layer
            ret.add(item); 
        } 
        item = new ArrayList<Integer> (); 
}
....
ret.add(item); 


2. add the current layer's result into the answer set at the last node of the layer. 

while (queue.size() != 0) { //so elegant!!!
....
     if (cur_num == 0) { //this layer is fininshed, prepare for next layer. 
        ret.add(item);
        cur_num = next_num;
        next_num = 0;
        item = new ArrayList<Integer> ();
}
....
To use the invariant for all layer, include the first layer. we use the current layer to prepare for the next layer, level 1 perpare for level 2 ... and so on. 

How about the first layer? (who prepare for it) if no layer parpare for it properly, the invariant would not be suitable for the first layer, which would result in complex checking and ugly codes!
A great solution: a dummy layer(layer -1), like the idea picked from dummy node. 
we simulate the dummy layer's function before entering the invarint.

        ArrayList<Integer> item = new ArrayList<Integer> ();
        int cur_num = 1;  
        int next_num = 0; 
        queue.offer(root);
        

Note: always fininsh the task at current layer!!! use proper invariant and dummy initialization!

My solution 1

public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        
        ArrayList<List<Integer>> ret = new ArrayList<List<Integer>> ();
        if (root == null)
            return ret;
        
        HashMap<TreeNode, Integer> level_map = new HashMap<TreeNode, Integer>();
        Queue<TreeNode> queue = new LinkedList<TreeNode> (); //very interesting
        ArrayList<Integer> item = null;
        
        int pre_level = -1; //prepare for the first node. 
        int cur_level = 0;
        queue.offer(root);
        level_map.put(root, 0);
        
        while (queue.size() != 0) {
            
            root = queue.poll();
            cur_level = level_map.get(root);
            
            if (cur_level != pre_level) {
                if (cur_level > 0) {//the first layer, has no previous level item.
                    ret.add(item); //add previous level's item into the ret.
                } 
                item = new ArrayList<Integer> (); //new a ArrayList for current level
            }
                        
            item.add(root.val);
            pre_level = cur_level; //update the pre_level
            
            if (root.left != null) {
                queue.offer(root.left);
                level_map.put(root.left, cur_level + 1);
            }
            
            if (root.right != null) {
                queue.offer(root.right);
                level_map.put(root.right, cur_level + 1);
            }
        }
        
        ret.add(item); ////for the last layer in tree, this kind of logic is very inelegant!!!
        
        return ret;
    }
}

Solution 2:

public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        
        ArrayList<List<Integer>> ret = new ArrayList<List<Integer>> ();
        if (root == null)
            return ret;
            
        TreeNode cur_node;
        Queue<TreeNode> queue = new LinkedList<TreeNode> (); //very interesting
        ArrayList<Integer> item = new ArrayList<Integer> ();

        int cur_num = 1; //the remained current-level nodes that have not been scanned.  
        int next_num = 0; //the next-level's nodes
        queue.offer(root);
        
        while (queue.size() > 0) {
            
            cur_node = queue.poll();
            item.add(cur_node.val);
            cur_num --;
            
            if (cur_node.left != null) {
                next_num ++;
                queue.offer(cur_node.left);
            }
            
            if (cur_node.right != null) {
                next_num ++;
                queue.offer(cur_node.right);
            }
            
            if (cur_num == 0) { //this layer is fininshed, prepare for next layer. 
                ret.add(item);
                cur_num = next_num;
                next_num = 0;
                item = new ArrayList<Integer> ();
            }
        }
        return ret;
    }
}
原文地址:https://www.cnblogs.com/airwindow/p/4216340.html