Algorithm: Binary Tree(1) -- Traversal Problems

问题列表:

利用DFS解决:

Binary Trees (Pre-order, In-order and Post-order) Traversal

Binary Trees‘s Largest Depth

222. Count Complete Tree Nodes

114. Flatten Binary Tree to Linked List

250. Count Univalue Subtrees

298. Binary Tree Longest Consecutive Sequence

297. Serialize and Deserialize Binary Tree

366. Find Leaves of Binary Tree

利用BFS解决:

199. Binary Tree Right Side View

314. Binary Tree Vertical Order Traversal



Binary Trees (Pre-order, In-order and Post-order) Traversal:


See this article: http://blog.csdn.net/firehotest/article/details/58535905


Binary Trees‘s Largest Depth:


使用Divide and Conquer


需要思考好最极端最小的情况返回什么, 分治只是把问题处理的数据分小了,问题还是不变的。所以这里的处理方法还是Math.max(两个返回值)。


public class Solution {  
    /** 
     * @param root: The root of binary tree. 
     * @return: An integer. 
     */  
       
    // private static depth = 0;  
    public int maxDepth(TreeNode root) {  
        // write your code here  
        if(root == null){//why this is the termination? because you don't need to consider the left and right children  
            return 0;  
        }  
        int temp1 = maxDepth(root.left);  
        int temp2 = maxDepth(root.right);  
        return 1+Math.max(temp1,temp2);  
          
    }  
}  


计算完全的二叉树的节点数目(Completed Binary Tree)

222. Count Complete Tree Nodes


利用满二叉树的高度和节点个数的性质:2^(h) - 1


We should use the feature of full binary tree. If a full binary tree’s height is h, then there are 2^(h) - 1 nodes in this tree. Then this problem can divide into two sub situations. 

If the most left height is equal to the right height, it is a full binary tree. We can use the 2^(h) - 1 to return the height. Otherwise, recursively call the same function for left sub tree and right sub tree. 


public class Solution {  
    private int leftHeight(TreeNode root) {  
        int count = 1;  
          
        while (root.left != null) {  
            count++;  
            root = root.left;  
        }  
          
        return count;  
    }  
      
    private int rightHeight(TreeNode root) {  
        int count = 1;  
          
        while (root.right != null) {  
            count++;  
            root = root.right;  
        }  
          
        return count;  
    }  
      
    public int countNodes(TreeNode root) {  
        if (root == null) {  
            return 0;  
        }  
          
        int height = 0;  
          
        if ((height = leftHeight(root)) == rightHeight(root)) {// full binary tree  
            return (1 << height) - 1;  
        } else {  
            return 1 + countNodes(root.left) + countNodes(root.right);  
        }  
    }  
}  


利用前序遍历的顺序把一个数扁平化成一个链表

114. 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


错误的一点:当你把右子孩子存好放进stack后,然后把左孩子赋给右孩子后,记得把左节点变成Null,不然整棵树变得很奇怪。


public class Solution {
    public void flatten(TreeNode root) {
        if (root == null) {
            return;
        }
        
        TreeNode tmp = root;
        LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
        
        while (tmp != null || !stack.isEmpty()) {
            while (tmp.left != null) {
                if (tmp.right != null) {
                    TreeNode rightSub = tmp.right;
                    stack.addFirst(rightSub);
                }
                tmp.right = tmp.left;
                tmp.left = null;// 错误点1
                tmp = tmp.right;
            }
            
            if (tmp.right != null) {
                tmp = tmp.right;
            } else {
                if (!stack.isEmpty()) {//错误点2
                    tmp.right = stack.removeFirst();
                }
                tmp = tmp.right;
            }
        }
    }
}


利用DFS递归解决的题目:

250. Count Univalue Subtrees


Given a binary tree, count the number of uni-value subtrees.


A Uni-value subtree means all nodes of the subtree have the same value.


For example:
Given binary tree,
              5
             / \
            1   5
           / \   \
          5   5   5
return 4.


思路:每一个点都可以以当前点作为root,然后进行DFS判断是否是Uni-value的子树。递归的函数只要传进一个值,每个点都判断一次即可。


public class Solution {
    private boolean recursion(TreeNode root, int val) {
        if (root.val != val) {
            return false;
        }
        
        if (root.left == null && root.right == null) {
            return true;
        }
        
        if (root.left != null && root.right != null) {
            return recursion(root.left, val) && recursion(root.right, val);
        } else if (root.left != null) {
            return recursion(root.left, val);
        } else {
            return recursion(root.right, val);
        }
    }
    
    public int countUnivalSubtrees(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        if (recursion(root, root.val)) {
            return 1 + countUnivalSubtrees(root.left) + countUnivalSubtrees(root.right);
        } else {
            return countUnivalSubtrees(root.left) + countUnivalSubtrees(root.right);
        }
    }
}


298. Binary Tree Longest Consecutive Sequence


Given a binary tree, find the length of the longest consecutive sequence path.


The path refers to any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The longest consecutive path need to be from parent to child (cannot be the reverse).


For example,
   1
    \
     3
    / \
   2   4
        \
         5
Longest consecutive sequence path is 3-4-5, so return 3.
   2
    \
     3
    / 
   2    
  / 
 1

Longest consecutive sequence path is 2-3,not3-2-1, so return 2.


public class Solution {
    private int longest = 0;
    
    private void recursion (TreeNode root, TreeNode prev, int length) {
        if (prev == null || prev.val + 1 == root.val) {
            length = length + 1;
        } else {
            length = 1;
        }
        
        longest = length > longest ? length : longest;
        
        if (root.left == null && root.right == null) {
            return;
        }
            
        if (root.left != null && root.right != null) {
            recursion(root.left, root, length);
            recursion(root.right, root, length);
        } else if (root.left != null) {
            recursion(root.left, root, length);
        } else if (root.right != null) {
            recursion(root.right, root, length);
        }
    }
    
    public int longestConsecutive(TreeNode root) {
        if (root == null) {//别忘了处理extreme cases
            return 0;
        }
        
        recursion(root, null, 0);
        return longest;
    }
}



通过一个Serialize的前序字符序列重构一棵树,前提是对于null的节点有专门的符号表示,这里我用"null"表示。注意,利用toString打印容器的话,元素和元素之间除了逗号,还有space。不要忽略这些细节。重构一棵树,最好还是用递归,否则很困难。

297. Serialize and Deserialize Binary Tree


Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.


Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure.


For example, you may serialize the following tree


    1
   / \
  2   3
     / \
    4   5
as "[1,2,3,null,null,4,5]", just the same as how LeetCode OJ serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself.


public class Codec {
    private void traversal(TreeNode root, List<String> rec) {
        if (root ==  null) {
            rec.add("null");
            return;
        }
        
        rec.add(String.valueOf(root.val));
        traversal(root.left, rec);
        traversal(root.right, rec);
        return;
    }
    

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        List<String> rec = new ArrayList<>();
        traversal(root, rec);
        String res = rec.toString();
        return res.substring(1, res.length() - 1);
    }
    
    private TreeNode buildTree(LinkedList<String> nodes) {
        if (nodes.isEmpty()) {
            return null;
        }
        
        String node = nodes.removeFirst();
        node = node.trim();//注意从集合打印出来的string元素之间除了逗号,还有空格
        if (node.equals("null")) {
            return null;
        }
        
        TreeNode cur = new TreeNode(Integer.valueOf(node));
        cur.left = buildTree(nodes);
        cur.right = buildTree(nodes);
        return cur;
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        String[] strNodes = data.split(",");
        LinkedList<String> nodes = new LinkedList<>(Arrays.asList(strNodes));
        
        return buildTree(nodes);
    }
}

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].


//递归函数做的事情:
//如果是null,返回-1。然后把当前节点的level = 1 + Max(左右节点的返回值)。
//然后一点trick的地方在于:当前结果集的size就是当前需要记录的level值,需要创建一个新的ArrayList放进答案集里面。

public class Solution {
    private int recursion(TreeNode root, List<List<Integer>> ans) {
        if (root == null) {
            return -1;
        }
        
        int left = recursion(root.left, ans);
        int right = recursion(root.right, ans);
        
        int level = 1 + Math.max(left, right);
        if (level == ans.size()) {
            List<Integer> tmp = new ArrayList<>();
            tmp.add(root.val);
            ans.add(tmp);
        } else {
            ans.get(level).add(root.val);
        }
        return level;
    }
    
    public List<List<Integer>> findLeaves(TreeNode root) {
        List<List<Integer>> ans = new ArrayList<>();
        recursion(root, ans);
        
        return ans;
    }
}



利用BFS解决的题目:
199. Binary Tree Right Side View


Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.


For example:
Given the following binary tree,
   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---
You should return [1, 3, 4].


思路:利用BFS,每次把当前层最后一个节点放进答案集了。注意,一般二叉树的BFS问题的模板都是用Null作为层与层之间的间隔,来区别。需要注意的是,如果当stack为空的时候就不要再放Null了,否则陷入死循环。


public class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        // 使用BFS,将每层的最后的元素加入答案集
        Queue<TreeNode> buff = new LinkedList<>();
        List<Integer> ans = new LinkedList<>();
        
        if (root == null) {
            return ans;
        }
        
        buff.offer(root);
        buff.offer(null);
        
        while (!buff.isEmpty()) {
            TreeNode tmp = null;
            while ((tmp = buff.poll()) != null) {
                if (buff.peek() == null) {
                    ans.add(tmp.val);
                }
                
                if (tmp.left != null) {
                    buff.offer(tmp.left);
                } 
                
                if (tmp.right != null) {
                    buff.offer(tmp.right);
                }
            }
            if (!buff.isEmpty()) {// 错误1
                buff.offer(null);
            }
        }
        
        return ans;
    }
}

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]
]

思路:先记录下来root属于哪个level。然后用TreeMap记录每个level有哪些节点。接着,遍历TreeMap的所有Value即可。需要注意,题目要求from top to bottom, from left to right. 所以必须使用BFS,否则同一个level的才可以保证from top to bottom的顺序。


public class Solution {
    private int detectRootPosit (TreeNode root) {
        TreeNode tmp = root;
        int left = 0;
        while (tmp.left != null) {
            left = left + 1;
            tmp = tmp.left;
        }
        return left;
    }
    
    public List<List<Integer>> verticalOrder(TreeNode root) {
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        if (root == null) {
            return ans;
        }
        
        Map<Integer, List<Integer>> levNodes = new TreeMap<Integer, List<Integer>>();
        
        int location = detectRootPosit(root);
        
        Queue<TreeNode> buff = new LinkedList<>();
        Queue<Integer> level = new LinkedList<>();
        
        buff.offer(root);
        level.offer(location);
        
        while (!buff.isEmpty()) {
            TreeNode tmp = buff.poll();
            int lev = level.poll();
            
            if (levNodes.containsKey(lev)) {
                levNodes.get(lev).add(tmp.val);
            } else {
                List<Integer> tmpList = new ArrayList<>();
                tmpList.add(tmp.val);
                levNodes.put(lev, tmpList);
            }
            
            if (tmp.left != null) {
                buff.offer(tmp.left);
                level.offer(lev - 1);
            }
            
            if (tmp.right != null) {
                buff.offer(tmp.right);
                level.offer(lev + 1);
            }
        }
        
        for (int key : levNodes.keySet()) {
            ans.add(levNodes.get(key));
        }
        
        return ans;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值