描述
请根据二叉树的前序遍历,中序遍历恢复二叉树,并打印出二叉树的右视图
示例

输入:
[1,2,4,5,3],[4,2,5,1,3]
返回值:
[1,3,5]

思路:
先通过前序遍历序列和中序遍历序列构造出二叉树,再通过bfs或者dfs打印出二叉树的右视图

方法一:递归+bfs
对于任意一颗树而言,前序遍历的形式总是
[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]

即根节点总是前序遍历中的第一个节点。而中序遍历的形式总是
[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]

  • 用Map保存中序遍历的值和对应索引,关键可以快速定位每一次根结点的位置

  • 在中序遍历中定位到根节点,知道左子树和右子树中的节点数目。由于同一颗子树的前序遍历和中序遍历的长度显然是相同的,因此我们就可以对应到前序遍历的结果中,
    对上述形式中的所有左右括号进行定位。

  • 递归地构造出左子树和右子树,再将这两颗子树接到根节点的左右位置。
    递归终止条件:当子树先序遍历为空,说明已经越过叶子结点,此时返回null

图片说明
再通过层序遍历,从左往右,一次入队一层的结点,将每一层结点的最右边结点添加到ArrayList中,因为数组长度需要可以动态扩展,因此先用ArrayList,后面将ArrayList转换为数组

图片说明

代码如下:

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 求二叉树的右视图
     * @param xianxu int整型一维数组 先序遍历
     * @param zhongxu int整型一维数组 中序遍历
     * @return int整型一维数组
     */
     Map<Integer,Integer>map=new HashMap();
    public int[] solve (int[] xianxu, int[] zhongxu) {
        // write code here

        for(int i=0;i<zhongxu.length;i++)
        {
            map.put(zhongxu[i],i);// 用Map保存中序遍历的值和对应索引
        }
        TreeNode root=build(xianxu,0,xianxu.length-1,zhongxu,0,zhongxu.length-1);
        return bfs(root);

    }
    TreeNode build(int[]xianxu,int xstart,int xend,int[]zhongxu,int zstart,int zend)
    {
        if(xstart>xend)return null;
        int rootval=xianxu[xstart];
        int index=map.get(rootval);//快速定位每一次根结点的位置
        int length=index-zstart;
        TreeNode root=new TreeNode(rootval);//构造根结点
        root.left=build(xianxu,xstart+1,xstart+length,zhongxu,zstart,index-1);//递归构造左子树
        root.right=build(xianxu,xstart+length+1,xend,zhongxu,index+1,zend);//递归构造右子树
        return root;
    }

    int[] bfs(TreeNode root)
    {
        if(root==null)return null;
        Deque<TreeNode>dq=new LinkedList<>();
        List<Integer>list=new ArrayList<>();
        dq.offer(root);
        for(TreeNode temp=root;!dq.isEmpty();)
        {
            //每一层结点数不同,因此队列的大小是不断变化的
            for(int size=dq.size();size>0;size--){
                //每次出队一个结点
                temp=dq.poll();
                if(temp.left!=null)dq.offerLast(temp.left);
                if(temp.right!=null)dq.offerLast(temp.right);

            }
            //数组添加的是每一层最后出队的结点,即最右边的结点
            list.add(temp.val);
        }   
        return list.stream().mapToInt(Integer::valueOf).toArray();
    }
}

复杂度分析:
时间复杂度:每个节点都入队出队了 1 次,所以bfs的时间复杂度为,递归次数为,每次递归定位根结点位置时间复杂度为常数级,因此时间复杂度为
空间复杂度: ,递归栈,哈希表和队列大小都为

方法二:递归+dfs
定义两个栈,记录搜索时经过的结点,记录对应结点的深度,定义一个哈希表(避免同一深度的结点重复入栈)存储二叉树右视图的结点
先将根结点入栈,栈非空时,结点出栈,对应结点的深度值出栈,维护二叉树的最大深度(方便后面将右视图对应深度的值转化为数组),如果不存在对应深度的结点,我们将结点插入右视图,继续将当前结点的左孩子和右孩子入栈,对应深度值入栈,注意先将左孩子入栈再将右孩子入栈,由于栈“先进后出”的特点,相同深度的左孩子和右孩子出栈时,右孩子会先出栈,并且插入右视图中,这样保证了哈希表中存储的是二叉树的右视图、
题目要求返回右视图的数组,将的value值存入数组并返回

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 求二叉树的右视图
     * @param xianxu int整型一维数组 先序遍历
     * @param zhongxu int整型一维数组 中序遍历
     * @return int整型一维数组
     */
     Map<Integer,Integer>map=new HashMap();
    public int[] solve (int[] xianxu, int[] zhongxu) {
        // write code here

        for(int i=0;i<zhongxu.length;i++)
        {
            map.put(zhongxu[i],i);//用Map保存中序遍历的值和对应索引
        }
        TreeNode root=build(xianxu,0,xianxu.length-1,zhongxu,0,zhongxu.length-1);
        return dfs(root);

    }
    TreeNode build(int[]xianxu,int xstart,int xend,int[]zhongxu,int zstart,int zend)
    {
        if(xstart>xend)return null;
        int rootval=xianxu[xstart];
        int index=map.get(rootval);//快速定位每一次根结点的位置
        int length=index-zstart;
        TreeNode root=new TreeNode(rootval);
        root.left=build(xianxu,xstart+1,xstart+length,zhongxu,zstart,index-1);//递归构造左子树
        root.right=build(xianxu,xstart+length+1,xend,zhongxu,index+1,zend);//递归构造右子树
        return root;
    }

    int[] dfs(TreeNode root) {
        Map<Integer, Integer> rightValueAtDepth = new HashMap<Integer, Integer>();//存储右视图的结点
        int max_depth = -1;
        Stack<TreeNode> stack = new Stack<TreeNode>();
        Stack<Integer> depthStack = new Stack<Integer>();
        stack.push(root);
        depthStack.push(0);

        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            int depth = depthStack.pop();
            if (node != null) {
                // 维护二叉树的最大深度
                max_depth = Math.max(max_depth, depth);
                // 如果不存在对应深度的节点我们才插入
                if (!rightValueAtDepth.containsKey(depth)) {
                    rightValueAtDepth.put(depth, node.val);
                }

                stack.push(node.left);//左孩子先进右孩子后进,保证出栈时右孩子先出
                stack.push(node.right);
                depthStack.push(depth + 1);
                depthStack.push(depth + 1);
            }
        }
        List<Integer> list = new ArrayList<Integer>();
        for (int depth = 0; depth <= max_depth; depth++) {
            list.add(rightValueAtDepth.get(depth));
        }
        return list.stream().mapToInt(Integer::valueOf).toArray();
    }

}

复杂度分析
时间复杂度 : 深度优先搜索最多访问每个结点一次,因此是线性复杂度,递归建树的时间复杂度也是,所以总的时间复杂度为
空间复杂度 : 。最坏情况下,栈内会包含接近树高度的结点数量,占用空间为,递归栈的大小也不超过
是树中的节点个数)