JAVA数据结构刷题 -- 二叉树进阶

一、二叉树前序递归遍历


根据方法的返回类型List<Integer>
遍历完二叉树后,返回一个整形的集合
前序遍历,表示按二叉树的根左右进行遍历


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


参考如下代码(附注解):

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();//创建一个集合用来存储二叉树的信息
        preorder(root,ret);//将二叉树的根和集合作为参数
        return ret;
    }
    public List<Integer> preorder(TreeNode root,List<Integer> list) {
    	//若根为空,表示此二叉树是一个空树,直接返回空即可
        if(root == null) {
            return null;
        }
        //若二叉树不为空
        //1.将根节点加到集合当中
        list.add(root.val);
        //2.将根的左子树作为根进行遍历
        preorder(root.left,list);
        //2.将根的右子树作为根进行遍历
        preorder(root.right,list);
        //返回最后的集合
        return list;
    }
}

二、二叉树前序非递归遍历

前序非递归遍历需要用到一个数据结构,首先,当二叉树为空树时,直接返回。
二叉树非空时,借助栈的结构,先判断当前结点是否为空,或者栈是否为空,当满足任意一个条件时,再在当前节点不为空的循环条件下,向栈内添加结点,并打印出来,接着将当前节点的左子树作为根重复进行循环打印,直到当前结点为空时,记录栈顶元素的值并将栈顶元素的右子树作为当前节点进行打印。
如下图示:


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


参考代码如下:

/**
     * 前序非递归遍历
     * 通过栈存储每一个二叉树结点
     * @param root
     */
    public void preOderNor(TreeNode root) {
        if(root == null) {
            return;
        }
        //创建栈
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        //判断当前结点或栈是否为空
        while (cur != null || !stack.empty()) {
            while (cur != null) {
                stack.push(cur);//入栈
                System.out.println(cur.val);//打印
                cur = cur.left;//当前节点的左子节点作为下一个结点
            }
            TreeNode top = stack.pop();//弹出并记录栈顶结点
            cur = top.right;//将该栈顶节点的右子节点作为当前节点进行入栈打印操作
        }
    }

三、中序后序还原二叉树

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

class Solution {
    public int postIndex;
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        postIndex = postorder.length - 1;
        return buildTreeChild(postorder,inorder,0,inorder.length-1);
    }
    private TreeNode buildTreeChild(int[] postorder, int[] inorder,int inbegin,int inend) {
        if(inbegin > inend) {
            return null;
        }
        //确定根节点
        TreeNode root = new TreeNode(postorder[postIndex]);
        //确定根节点值在中序遍历中的位置(下标)
        int rootIndex = findIndex(inorder,inbegin,inend,root.val);
        postIndex--;
        //遍历,先遍历根的右子节点,再遍历根的左子节点
        root.right = buildTreeChild(postorder,inorder,rootIndex+1,inend);
        root.left = buildTreeChild(postorder,inorder,inbegin,rootIndex-1);       
        return root;
    }
    //找到根节点在中序遍历数组中的位置,返回所在下标
    private int findIndex(int[] inorder,int inbegin,int inend,int key) {
        for(int i = inbegin;i <= inend; i++) {
            if(inorder[i] == key){
                return i;
            }
        }
        return -1;
    }
}

四、前序中序还原二叉树

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

class Solution {
    public int preIndex = 0;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTreeChild(preorder,inorder,0,inorder.length-1);
    }
    private TreeNode buildTreeChild(int[] preorder, int[] inorder,int inbegin,int inend) {
        if(inbegin > inend) {
            return null;
        }
        //确定根节点
        TreeNode root = new TreeNode(preorder[preIndex]);
        //确定根节点值在中序遍历中的位置(下标)
        int rootIndex = findIndex(inorder,inbegin,inend,root.val);
        preIndex++;
        //遍历,先遍历根的左子节点,再遍历根的右子节点
        root.left = buildTreeChild(preorder,inorder,inbegin,rootIndex-1);
        root.right = buildTreeChild(preorder,inorder,rootIndex+1,inend);
        return root;
    }
     //找到根节点在中序遍历数组中的位置,返回所在下标
    private int findIndex(int[] inorder,int inbegin,int inend,int key) {
        for(int i = inbegin;i <= inend; i++) {
            if(inorder[i] == key){
                return i;
            }
        }
        return -1;
    }
}

五、两个节点的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null) return null;
        if(p == root || q == root) return root;
        TreeNode leftRet = lowestCommonAncestor(root.left,p,q);
        TreeNode rightRet = lowestCommonAncestor(root.right,p,q);
        if(leftRet != null && rightRet != null) {
            return root;
        }else if(leftRet != null){
            return leftRet;
        }else {
            return rightRet;
        }
    }
}

六、二叉树的层序遍历

给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

这道题目用到了队列,因为返回值时集合,需要创建一个集合,当二叉树为空时,返回一个空的集合,二叉树不为空,将当前的根节点加入到队列中,当队列不为空时,弹出队头结点并记录他的值,判断对头的左子节点和右子节点是否存在,若存在就加入到队列中进行循环,直到队列为空,循环结束,每次都在0下标位置向集合中添加结点,最后返回集合。

class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> ret = new LinkedList<>();
        if (root == null) {
            return ret;
        }
        queue.offer(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            List<Integer> list = new ArrayList<>();
            while (size != 0) {
                TreeNode top = queue.poll();
                list.add(top.val);
                if (top.left != null) {
                    queue.offer(top.left);
                }
                if (top.right != null) {
                    queue.offer(top.right);
                }
                size--;
            }
            //关键点:通过集合的应用,每次添加都从0下标开始,保证题目的要求:自底向上
            ret.add(0,list);
        }
        return ret;
    }
}

七、根据二叉树创建字符串

给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。
空节点使用一对空括号对 “()” 表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。

class Solution {
    public String tree2str(TreeNode root) {
        if(root == null) return null;
        StringBuilder stringBuilder = new StringBuilder();
        tree2strChild(root,stringBuilder);
        return stringBuilder.toString();
    }
    private void tree2strChild(TreeNode root ,StringBuilder stringBuilder) {
        if(root == null) return;
        stringBuilder.append(root.val);
        if(root.left != null) {
            stringBuilder.append("(");
            tree2strChild(root.left,stringBuilder);
            stringBuilder.append(")");
        }else {
            if(root.right == null) {
                return;
            }else {
                stringBuilder.append("()");
            }
        }
        if(root.right != null) {
            stringBuilder.append("(");
            tree2strChild(root.right,stringBuilder);
            stringBuilder.append(")");
        }else {
            return;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶落闲庭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值