FindLeavesOfBinaryTree [source code]


public class FindLeavesOfBinaryTree {
static
/******************************************************************************/
public class Solution {
    public List<List<Integer>> findLeaves(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        dfs(res, root);
        return res;
    }

    public int dfs(List<List<Integer>> levels, TreeNode root) {
        if (root == null) return 0;
        int left = dfs(levels, root.left);
        int right = dfs(levels, root.right);
        int dist = Math.max(left, right) + 1;
        if (levels.size() < dist) {
            List<Integer> level = new ArrayList<>();
            level.add(root.val);
            levels.add(level);
        } else {
            List<Integer> level = levels.get(dist - 1);
            level.add(root.val);
        }
        return dist;
    }
}
/******************************************************************************/

    public static void main(String[] args) {
        FindLeavesOfBinaryTree.Solution tester = new FindLeavesOfBinaryTree.Solution();
    }
}

这题首先笨办法是很简单的, 就是一个while(tree.size > 1)这样的循环下面, 每一个iteration来一个DFS就行了, 但是这样最后的time就非常差, 应该是lgN * N;

比较理想的解估计是直接一个DFS就能做完; 先看看能不能想到这个解法;

这一题的DFS必须要PostOrder;

这个题目整体最后想到的办法还是很简单的, 其实这个题目就是一个最pure的用recursion来做的题目; 我们当初第一次做depth的题目的时候, 还觉得那个题目对于recursion的使用不够直接; 这里这个就真的够直接了, 因为leaf就直接是对应(返回)的0, 然后每一个node的返回值, 都可以直接根据自己的两个child的返回值直接计算, 不需要任何的tag或者accum;

至于细节的逻辑就没有什么特别好说的了; recursion内部的处理其实就是一个判断当前的leaf level对应的list是否已经被init. 如果没有, 就需要初始化一下; 这个问题只要你遵守PostOrder, 那么就很好处理, 不会出现跳level, 也就是说比如我们levels里面现在只有最底下的对应返回值是1的这一层的list, 结果你突然就跑到了3的这一层这样的情况; 只要你是PostOrder, 或者是InOrder好像也行, 那么当你走到一个level的时候, 你就可以确定下面的level的对应的list肯定全部已经被init, 你自己当前所在的level的list如果还没有被初始化, 那么现在的levels的size肯定是dist - 1.

本来一个想法是让leaf(左右child都是Null的判断)的dist作为0的, 但是后来想想这样Null自己的值就不太好处理(其实如果也作为0或者作为-1也是可以的, 因为这里算的是-1), 所以干脆就用1了; 这样最后dist是1的对应的list在levels里面的index就是0, -1操作一下就行了, 也不是什么很大的问题;

最后的速度是1ms (21%), 其实是submission最优解了;


这个是discussion里面看到的:

For this question we need to take bottom-up approach. The key is to find the height of each node. Here the definition of height is:
The height of a node is the number of edges from the node to the deepest leaf. --CMU 15-121 Binary Trees
I used a helper function to return the height of current node. According to the definition, the height of leaf is 0. h(node) = 1 + max(h(node.left), h(node.right)).
The height of a node is also the its index in the result list (res). For example, leaves, whose heights are 0, are stored in res[0]. Once we find the height of a node, we can put it directly into the result.

底下好像有人讨论, 真正面试的时候除了返回这个list, 你是否需要modify这个input, 也就是给你的这个tree, 最后就是要被你摘的啥也不剩;

这个是在我的逻辑的基础上稍微优化了一下:

private int findLeavesHelper(List<List<Integer>> list, TreeNode root) {  
    if (root == null) {  
        return -1;  
    }  
    int leftLevel = findLeavesHelper(list, root.left);  
    int rightLevel = findLeavesHelper(list, root.right);  
    int level = Math.max(leftLevel, rightLevel) + 1;  
    if (list.size() == level) {  
        list.add(new ArrayList<>());  
    }  
    list.get(level).add(root.val);  
    root.left = root.right = null;  
    return level;  
}

用conditional overridding来处理level list not initialized的情况, 这个想法其实是不错的, 就跟你要update map entry的时候的思路一样, 那个时候, depending on whether the key is already in the map, 也是可以用overriding来完成一个逻辑;


另外discussion上居然还有人贴暴力解:

public class Solution {  
    public List<List<Integer>> findLeaves(TreeNode root) {  

        List<List<Integer>> leavesList = new ArrayList< List<Integer>>();  
        List<Integer> leaves = new ArrayList<Integer>();  

        while(root != null) {  
            if(isLeave(root, leaves)) root = null;  
            leavesList.add(leaves);  
            leaves = new ArrayList<Integer>();  
        }  
        return leavesList;  
    }  

    public boolean isLeave(TreeNode node, List<Integer> leaves) {  

        if (node.left == null && node.right == null) {  
            leaves.add(node.val);  
            return true;  
        }  

        if (node.left != null) {  
             if(isLeave(node.left, leaves))  node.left = null;  
        }  

        if (node.right != null) {  
             if(isLeave(node.right, leaves)) node.right = null;  
        }  

        return false;  
    }  
}

这是另外一个:

public class Solution {  
    public List<List<Integer>> findLeaves(TreeNode root) {  
        List<List<Integer>> res = new ArrayList<List<Integer>>();  
        while (root != null) {  
            List<Integer> temp = new ArrayList<Integer>();  
            root = removeLeaves(root, temp);  
            res.add(temp);  
        }  
        return res;  
    }  

    private TreeNode removeLeaves(TreeNode root, List<Integer> temp) {  
        if (root == null) return null;  
        if (root.left == null && root.right == null) {  
            temp.add(root.val);  
            return null;  
        }  
        root.left = removeLeaves(root.left, temp);  
        root.right = removeLeaves(root.right, temp);  
        return root;  
    }  
}

没时间懒得看了, 以后再说了; 其实真的非要modify input的话我感觉也挺没有意义的, 你全都摘完了之后, 不就肯定是空的么, 有什么好modify step by step的;

这个题目的discussion看完真的是感觉菜比其实也挺多的;

这个题目的最优解相对来说并不是特别难想; 不过想想我这个话也不对, 有些问题我自己也菜比过, 最后写出来的解法比最简单的解法要复杂的多;


这个是一个妹子分享的关于topological sort的做法:

We delete nodes layer by layer: for each round,we delete the nodes whose outdegree=0, and update their parent's outdegree. It's very similar similar with what we did in Topological Sort(in TopoSort,each round we delete those whose indegree=1 and iterate).

Use two HashMap, one for recording the outdegree of each TreeNode, and one for recording the parent of each TreeNode; first traverse the tree and load the maps, and then put those whose outdegree=0 into a Deque and iterate until running out of nodes.


public class Solution{  
    public List<List<Integer>> findLeaves(TreeNode root){  
         List<List<Integer>> res=new ArrayList<>();  

        //record outdegree of every node  
        HashMap<TreeNode,Integer> outdegree=new LinkedHashMap<TreeNode,Integer>();  
        //record parent of every node  
        HashMap<TreeNode,TreeNode> parent=new HashMap<TreeNode,TreeNode>();  
        loadMap(root,outdegree,parent);  

        Deque<TreeNode> q=new LinkedList<TreeNode>();  
        for(TreeNode node:outdegree.keySet()){  
            if(outdegree.get(node)==0){  
                q.offer(node);  
            }  
        }  
        while(!q.isEmpty()){  
            int size=q.size();  
            List<Integer> tmp=new ArrayList<Integer>();  
            for(int i=0;i<size;i++){  
                TreeNode t=q.poll();  
                tmp.add(t.val);  
                if(t!=root){  
                    outdegree.put(parent.get(t),outdegree.get(parent.get(t))-1);  
                    if(outdegree.get(parent.get(t))==0){  
                        q.offer(parent.get(t));  
                    }  
                }  
            }  
            res.add(tmp);  
        }  

        return res;  
    }  

    public void loadMap(TreeNode root,HashMap<TreeNode,Integer> outdegree,HashMap<TreeNode,TreeNode> parent){  
        if(root==null){  
            return;  
        }  
        if(root.left==null&&root.right==null){  
            outdegree.put(root,0);  
            return;  
        }  

        int degree=0;  
        if(root.left!=null){  
            degree++;  
            parent.put(root.left,root);  
        }  
        if(root.right!=null){  
            degree++;  
            parent.put(root.right,root);  
        }  
        outdegree.put(root,degree);  

        loadMap(root.left,outdegree,parent);  
        loadMap(root.right,outdegree,parent);  
    }  
}

看起来有点复杂, 暂时不看了, 反正后面还是有时间去看. 先记录在这里, 然后在G4G上面看过文章之后什么时候有时间再来看;


Problem Description

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

Explanation:

  1. Removing the leaves [4, 5, 3] would result in this tree:

       1  
      /   
     2            
    
  2. Now removing the leaf [2] would result in this tree:

       1            
    
  3. Now removing the leaf [1] would result in the empty tree:

       []           
    

    Returns [4, 5, 3], [2], [1].

Credits:
Special thanks to @elmirap for adding this problem and creating all test cases.

Difficulty:Medium
Total Accepted:16.8K
Total Submissions:28.4K
Contributor: LeetCode
Companies
linkedin
Related Topics
tree depth-first search

results matching ""

    No results matching ""