zoukankan      html  css  js  c++  java
  • [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;
        }
    }
  • 相关阅读:
    下载远程url文件(或者文件流)到本地
    在jsp中出现异常后应该停止往下执行的情况,怎么处理?
    用js函数处理事件时,有时候可能因为页面部分组件不需要显示,但仍需要执行js,会有报错,但是不想暴露页面,是业务正常进行。。。。
    Linux shell 逻辑判断符号
    java生成excel并可以导出
    timer定时器
    StringBuffer的使用
    jsp不能使用return时候,如何在出异常时退出,不在向下执行
    java 调用linux脚本例子
    关于File.separator 文件路径:wind与linux下路径问题 .
  • 原文地址:https://www.cnblogs.com/airwindow/p/4216340.html
Copyright © 2011-2022 走看看