• 二叉树--经典面试题2


    目录

    1.根据一棵树的前序遍历与中序遍历构造二叉树

    2.根据一棵树的中序遍历与后序遍历构造二叉树

    3.二叉树创建字符串

    4.二叉树前序非递归遍历实现

    5.二叉树中序非递归遍历实现

    6.二叉树后序非递归遍历实现

    7.二叉树的最大宽度

    8.合并二叉树


    1.根据一棵树的前序遍历与中序遍历构造二叉树

    • 题目描述

    •  代码

    1. //前序遍历的下标放在外面,防止在建左树的时候,递出去++,归回来又变成原来的值了
    2. public int preIndex = 0;
    3. public TreeNode buildTreeChild(int[] preorder, int[] inorder, int inbegin, int inend) {
    4. if(inbegin > inend) return null;
    5. TreeNode root = new TreeNode(preorder[preIndex]);
    6. //找根节点在中序遍历的位置
    7. int rootPos = findInorderPos(inorder, inbegin, inend, preorder[preIndex]);
    8. preIndex++;
    9. root.left = buildTreeChild(preorder, inorder, inbegin, rootPos - 1);
    10. root.right = buildTreeChild(preorder, inorder, rootPos + 1, inend);
    11. return root;
    12. }
    13. private int findInorderPos(int[] inorder, int inbegin, int inend, int val) {
    14. for(int i = inbegin; i <= inend; i++) {
    15. if(inorder[i] == val) {
    16. return i;
    17. }
    18. }
    19. return -1;
    20. }
    21. public TreeNode buildTree(int[] preorder, int[] inorder) {
    22. return buildTreeChild(preorder, inorder, 0, inorder.length-1);
    23. }
    • 图解

    •  思路

    1.定义 preIndex 遍历前序遍历这个数组

    2.在中序遍历的 ib - ie 之间,找到 ri 的下标位置

    3.此时 ri 左边的就是左树,ri 右边的就是右树

    4.递归创建左树和递归创建右树

    5.当 ib > ie 的时候,说明没有了左树或者右树

    当然这种做法在oj 能跑过,但时间复杂度还是过高了,等我学完哈希map回过头来优化代码,,,


    2.根据一棵树的中序遍历与后序遍历构造二叉树

    • 题目描述

    • 代码 

    1. public int postIndex = 0;
    2. //postIndex从后序遍历这个数组的最后开始,那么就是根,右,左
    3. public TreeNode buildTreeChild(int[] postorder, int[] inorder, int inbegin, int inend) {
    4. if(inbegin > inend) return null;
    5. TreeNode root = new TreeNode(postorder[postIndex]);
    6. //找根节点在中序遍历的位置
    7. int rootPos = findInorderPos(inorder, inbegin, inend, postorder[postIndex]);
    8. postIndex--;
    9. root.right = buildTreeChild(postorder, inorder, rootPos + 1, inend);
    10. root.left = buildTreeChild(postorder, inorder, inbegin, rootPos - 1);
    11. return root;
    12. }
    13. private int findInorderPos(int[] inorder, int inbegin, int inend, int val) {
    14. for(int i = inbegin; i <= inend; i++) {
    15. if(inorder[i] == val) {
    16. return i;
    17. }
    18. }
    19. return -1;
    20. }
    21. public TreeNode buildTree(int[] inorder, int[] postorder) {
    22. postIndex = postorder.length - 1;
    23. return buildTreeChild(postorder, inorder, 0, inorder.length-1);
    24. }
    • 分析

    这道题和上一道题是差不多的,只需要将前序遍历数组起初的下标改成这里后序遍历数组中的最后一个下标,因为后序遍历是左右根,所以从后面开始,就变了根左右,其余的思路都是一样的。


    3.二叉树创建字符串

    • 题目描述

    • 代码 (建议跟着图解看这道题)

    1. public void tree2strChild(TreeNode cur, StringBuilder sb) {
    2. sb.append(cur.val);
    3. //先走左边
    4. if(cur.left != null) {
    5. sb.append("(");
    6. tree2strChild(cur.left, sb);
    7. sb.append(")");
    8. } else {
    9. if(cur.right == null) {
    10. return;
    11. } else {
    12. sb.append("()");
    13. }
    14. }
    15. //回退完了之后,再走右边
    16. if(cur.right == null) {
    17. return;
    18. } else {
    19. sb.append("(");
    20. tree2strChild(cur.right, sb);
    21. sb.append(")");
    22. }
    23. }
    24. public String tree2str(TreeNode root) {
    25. StringBuilder sb = new StringBuilder();
    26. tree2strChild(root, sb);
    27. return sb.toString();
    28. }
    •  图解

    做这道题,如果看不懂题,必须要跟着例子图,走代码,请看下面图解:

    首先要把几种情况分清楚:

     


     4.二叉树前序非递归遍历实现

    • 代码

    1. public List<Integer> preorderTraversal(TreeNode root) {
    2. List<Integer> list = new ArrayList<>();
    3. if(root == null) return list;
    4. Stack<TreeNode> stack = new Stack<>();
    5. TreeNode cur = root;
    6. //这里是一个难点,需要倒回来写这个循环
    7. while(!stack.empty() || cur != null) {
    8. while(cur != null) {
    9. stack.push(cur);
    10. list.add(cur.val);
    11. cur = cur.left;
    12. }
    13. TreeNode top = stack.pop();
    14. cur = top.right;
    15. }
    16. return list;
    17. }
    • 图解


    5.二叉树中序非递归遍历实现(与4相似)

    • 代码

    1. public List<Integer> inorderTraversal(TreeNode root) {
    2. List<Integer> list = new ArrayList<>();
    3. if(root == null) return list;
    4. Stack<TreeNode> stack = new Stack<>();
    5. TreeNode cur = root;
    6. while(!stack.empty() || cur != null) {
    7. while(cur != null) {
    8. stack.push(cur);
    9. cur = cur.left;
    10. }
    11. TreeNode top = stack.pop();
    12. list.add(top.val);//先添加左
    13. cur = top.right;//判断以 cur.left 作为根的这棵树有没有右孩子
    14. }
    15. return list;
    16. }
    • 图解


    6.二叉树后序非递归遍历实现

    • 代码

    1. public List<Integer> postorderTraversal(TreeNode root) {
    2. List<Integer> list = new ArrayList<>();
    3. if(root == null) return list;
    4. Stack<TreeNode> stack = new Stack<>();
    5. TreeNode cur = root;
    6. TreeNode prev = null;
    7. while(!stack.empty() || cur != null) {
    8. while(cur != null) {
    9. stack.push(cur);
    10. cur = cur.left;
    11. }
    12. TreeNode top = stack.peek();
    13. //因为是 左 右 根 ,所以添加元素前需要判断一下是否已添加
    14. if(top.right == null || top.right == prev) {
    15. stack.pop();
    16. list.add(top.val);
    17. prev = top;//添加过的标记一下
    18. } else {
    19. cur = top.right;
    20. }
    21. }
    22. return list;
    23. }

    这里要注意的是,因为 根 左 右 ,而每次循环都把左右子树当成根了,那么添加结点的时候,就会出现这样一个问题:

    所以这个题的难点就是每次添加完一个结点后需要记录一下!!!


    7.二叉树的最大宽度

    • 题目描述

    假说 :

    从题目描述和例子来看,如果这棵二叉树是按照层序遍历来编号,最大宽度似乎就是求每一层最右边结点编号减去最左边结点编号的差值+1,然后取其中的最大值。

    • 代码 (dfs)

    1. //最大宽度必须定义在外面,否则每次递归都重新定义了
    2. int maxW;
    3. public int widthOfBinaryTree(TreeNode root) {
    4. int index = 1;//值
    5. int level = 1;//层数
    6. dfs(root,1,1,new ArrayList<>());
    7. return maxW;
    8. }
    9. private void dfs(TreeNode root, int level, int index, List<Integer> leftList) {
    10. if(root == null) return;
    11. //层数大于集合元素个数,就添加-->即添加所有最左边元素
    12. if(level > leftList.size()) {
    13. leftList.add(index);
    14. }
    15. //所有除了最左边结点减去最左边的结点的差值加一就等于两者之间的宽度,不断筛选最大的宽度
    16. maxW = Math.max(maxW,index - leftList.get(level - 1) + 1);
    17. //注意index可不敢++
    18. dfs(root.left, level + 1, index * 2, leftList);
    19. dfs(root.right, level + 1, index * 2 + 1, leftList);
    20. }
    •  图解


    8.合并二叉树

    • 题目描述

    •  代码

    1. public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
    2. if(root1 == null) {
    3. return root2;
    4. }
    5. if(root2 == null) {
    6. return root1;
    7. }
    8. TreeNode newRoot = new TreeNode(root1.val + root2.val);
    9. newRoot.left = mergeTrees(root1.left,root2.left);//新的左子树
    10. newRoot.right = mergeTrees(root1.right,root2.right);//新的右子树
    11. return newRoot;
    12. }
    • 思路

    1.在递归的过程中,当一棵树为空树时,直接返回另一棵树的根;

    2.如果两树的根都不为空,新的根的值就是两树根值的和。

    谢谢观看!!!

  • 相关阅读:
    linux-系统硬件信息查看方法
    【深度学习实验】前馈神经网络(final):自定义鸢尾花分类前馈神经网络模型并进行训练及评价
    前端Sortable拖拽实现排序
    TCO-PEG-FITC 荧光素-聚乙二醇-反式环辛烯 TCO-PEG-荧光素
    雅虎、领英接连退出中国,开发者:GitHub 也会受到影响吗?
    java反射
    【MySQL】MySQL的存储过程(1)
    【搞定k8s】k8s轻松部署Dashboard管理集群
    Java中如何使用BufferedInputStream,BufferedOutputStream分批快速读取大文件呢?
    python学习27
  • 原文地址:https://blog.csdn.net/xaiobit_hl/article/details/125010271