Binary Tree Right Side View

来源:互联网 发布:女友花钱大手大脚 知乎 编辑:程序博客网 时间:2024/06/11 14:20

https://leetcode.com/problems/binary-tree-right-side-view/

Given a binary tree, imagine yourself standing on theright 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].

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */


public List<Integer> rightSideView(TreeNode root)


这一题的实质上是要求返回树里面每一层里最右边的那个node。所以本质上来说最右边的那个点。所以最直观的做法是BFS,从右往左扫,放入每一层的第一个节点即可。

这一题不像minDepth,BFS有着比DFS效率更高的解法,minDepth里BFS扫到第一个符合条件的点就可以停,剩下的点可以不用扫了,DFS需要额外加一个统计层数的全局变量才能达到BFS的效果。然而这一题无论如何都是要扫光全部的节点的。所以还是得老老实实的扫完整棵树,复杂度是O(N)

根据BFS算法,给出代码如下:

    public List<Integer> rightSideView(TreeNode root) {        Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();        nodeQueue.add(root);        List<Integer> result = new LinkedList<Integer>();        if(root == null){            return result;        }        while(!nodeQueue.isEmpty()){            int size = nodeQueue.size();            for(int i = 0; i < size; i++){                TreeNode currentNode = nodeQueue.poll();                if(i == 0){                    result.add(currentNode.val);                }                if(currentNode.right != null){                    nodeQueue.add(currentNode.right);                }                if(currentNode.left != null){                    nodeQueue.add(currentNode.left);                }            }        }        return result;    }

这一题依旧是可以有DFS的解的,常见关于树的DFS有三种,中左右(pre-order),左中右(in-order),左右中(post-order)。

这一次做的是另外的DFS,中右左,这样能保证当前层遇到的第一个节点就是我们所要求的。所以只需要维护一个当前所遇到的最大层级,以及当前节点所在的层级,如果当前节点所在的层级比维护的最大层级大,就表示我们现在的节点是right most的节点。这个时候更新一下最大层级以及将当前节点的数字加入结果即可。


先给出递归的做法

    public List<Integer> rightSideView(TreeNode root) {        List<Integer> result = new LinkedList<Integer>();        ArrayList<Integer> maxDepth = new ArrayList<Integer>();        maxDepth.add(-1);        helper(maxDepth, root, result, 0);        return result;    }        public void helper(ArrayList<Integer> maxDepth, TreeNode root, List<Integer> result, int depth){        if(root != null){            if(depth > maxDepth.get(0)){                maxDepth.set(0, depth);                result.add(root.val);            }            helper(maxDepth, root.right, result, depth + 1);            helper(maxDepth, root.left, result, depth + 1);        }    }

因为这也是一个简单的DFS递归,所以我们也可以弄出一个用stack做的循环做法。

先给出一个,效仿了post order的。(事实上这也是一个preorder,但因为我们要跟踪当前层级的级数,所以不得已用了post order的做法)

    public List<Integer> rightSideView(TreeNode root) {        List<Integer> result = new LinkedList<Integer>();        TreeNode currentNode = root, prevNode = null;//我们需要维护一个前任节点来判断我们上一次遍历的节点是父亲节点还是当前节点的左或右节点        Stack<TreeNode> dfsStack = new Stack<TreeNode>();        int currentLength = 0, maxLength = -1;        while(!dfsStack.isEmpty() || currentNode != null){            if(currentNode != null){                currentLength++;                if(currentLength > maxLength){//在DFS遍历里,我们遇到中的时候就需要输出,这里是中右左的中。所以我们需要判断当前节点是否为我们所求的输出。                    result.add(currentNode.val);                    maxLength = currentLength;                }                dfsStack.push(currentNode);                prevNode = currentNode;                currentNode = currentNode.right;            }else{                currentNode = dfsStack.peek();                if(currentNode.left != null && prevNode != currentNode.left){//如果之前的节点不为当前节点的左子节点,就往左走。因为右边已经走过了。                    currentNode = currentNode.left;                }else{                    currentLength--;//因为我们需要维护currentLength,所以我们只能一级级往上返回。所以才在这里引起了多余的一步步往上走的过程。                    dfsStack.pop();                    prevNode = currentNode;                    currentNode = null;                }            }        }        return result;    }

事实上这是一个preorder,但是上面的代码却更类似于一个postorder的做法,事实上preorder在遍历完子节点之后,是不需要那么麻烦的一级级的返回的。至于怎么做,下面引进一个新的做法。因为leetcode不支持Guava的Pair类,也不支持Entry的实现类(至少我木有找到)。所以我们得先自己写一个pair类,来维护当前节点以及所对应的层级数,然后用类似preorder的循环做法去做就可以了。

    class Pair{        TreeNode currentNode;        int curDepth;        Pair(TreeNode node, int depth){            currentNode = node;            curDepth = depth;        }    }        public List<Integer> rightSideView(TreeNode root) {        List<Integer> result = new LinkedList<Integer>();        TreeNode currentNode = root;        Stack<Pair> dfsStack = new Stack<Pair>();        int currentDepth = 0, maxDepth = -1;        while(!dfsStack.isEmpty() || currentNode != null){            if(currentNode != null){                currentDepth++;                if(currentDepth > maxDepth){                    result.add(currentNode.val);                    maxDepth = currentDepth;                }                dfsStack.push(new Pair(currentNode, currentDepth));                currentNode = currentNode.right;            }else{                currentNode = dfsStack.peek().currentNode;                currentDepth = dfsStack.pop().curDepth;                currentNode = currentNode.left;            }        }        return result;    }
上述代码基本可以参见preorder traversal

0 0
原创粉丝点击