面试 TOP101 二叉树专题题解汇总Java版(BM23 —— BM41)

刷题挑战链接

二叉树

题号题目名称核心思路时间复杂度空间复杂度代码亮点牛客原题链接
BM23二叉树的前序遍历递归实现,先访问根节点,再递归遍历左子树,最后递归遍历右子树O(n)O(n)使用辅助函数 preorder,逻辑清晰,递归终止条件明确🔗 直达
BM24二叉树的中序遍历递归实现,先递归遍历左子树,访问根节点,再递归遍历右子树O(n)O(n)递归逻辑简洁,通过辅助函数 inorder 实现🔗 直达
BM25二叉树的后序遍历递归实现,先递归遍历左子树,再递归遍历右子树,最后访问根节点O(n)O(n)递归逻辑清晰,辅助函数 postorder 实现后序遍历🔗 直达
BM26求二叉树的层序遍历使用队列实现广度优先搜索,逐层访问节点O(n)O(n)使用队列存储待访问的节点,逐层处理🔗 直达
BM27按之字形顺序打印二叉树层序遍历结合反转操作,偶数层反转当前层的节点值O(n)O(n)使用队列实现层序遍历,通过 Collections.reverse 反转偶数层🔗 直达
BM28二叉树的最大深度使用队列实现广度优先搜索,逐层访问节点,计算最大深度O(n)O(n)使用队列存储待访问的节点,逐层处理,每层深度加1🔗 直达
BM29二叉树中和为某一值的路径(一)递归或广度优先搜索,记录从根节点到叶子节点的路径和O(n)O(n)递归方法简洁,广度优先搜索使用 Pair 类记录路径和🔗 直达
BM30二叉搜索树与双向链表递归或非递归中序遍历,将二叉搜索树转换为双向链表O(n)O(n)递归方法中使用全局变量 headpre,非递归方法使用栈🔗 直达
BM31对称的二叉树递归或层序遍历,判断二叉树是否对称O(n)O(n)递归方法中使用辅助函数 chk,层序遍历使用队列🔗 直达
BM32合并二叉树递归合并两棵二叉树,对应节点值相加O(n)O(n)递归方法简洁,新建节点 head 作为合并后的根节点🔗 直达
BM33二叉树的镜像递归或栈实现,交换每个节点的左右子树O(n)O(n)递归方法简洁,栈方法使用迭代🔗 直达
BM34判断是不是二叉搜索树递归或中序遍历,判断中序遍历结果是否递增O(n)O(n)递归方法中使用全局变量 pre,中序遍历方法使用栈🔗 直达
BM35判断是不是完全二叉树使用队列实现层序遍历,检查是否为完全二叉树O(n)O(n)使用队列存储待访问的节点,逐层处理🔗 直达
BM36判断是不是平衡二叉树递归计算子树高度,判断是否平衡O(n)O(n)使用辅助函数 depth,递归计算子树高度🔗 直达
BM37二叉搜索树的最近公共祖先递归或路径比较,找到最近公共祖先O(n)O(n)使用辅助函数 getPath,记录路径🔗 直达
BM38在二叉树中找到两个节点的最近公共祖先递归或路径比较,找到最近公共祖先O(n)O(n)使用辅助函数 lowestCommonAncestor,递归查找🔗 直达
BM39序列化二叉树递归或层序遍历,序列化二叉树O(n)O(n)使用辅助函数 SerializeFuctionDeserializeFuction🔗 直达
BM40重建二叉树递归或栈遍历,根据前序和中序遍历重建二叉树O(n)O(n)使用辅助函数 buildTree,递归重建🔗 直达
BM41输出二叉树的右视图递归或层序遍历,输出二叉树的右视图O(n)O(n)使用辅助函数 rightSideView,层序遍历🔗 直达

✅ 建议复习顺序(由易到难):

BM23 → BM24 → BM25 → BM26 → BM27 → BM29 → BM30 → BM31 → BM32 → BM33 → BM34 → BM35 → BM36 → BM37 → BM38 → BM39 → BM40 → BM41

BM23 二叉树的前序遍历

二叉树的前序遍历_牛客题霸_牛客网
https://www.nowcoder.com/practice/5e2135f4d2b14eb8a5b06fab4c938635?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj

import java.util.*;

public class Solution {
    void preorder(List<Integer> list, TreeNode root){ // 1. 定义前序遍历辅助方法
        if(root == null) return ; // 2. 如果当前节点为空,直接返回
        list.add(root.val); // 3. 访问当前节点,将值加入列表
        preorder(list,root.left); // 4. 递归遍历左子树
        preorder(list,root.right); // 5. 递归遍历右子树
    }
    public int[] preorderTraversal (TreeNode root) {
        List<Integer> list = new ArrayList(); // 6. 创建一个列表用于存储遍历结果
        preorder(list,root); // 7. 调用前序遍历辅助方法
        int [] res = new int [list.size()]; // 8. 创建一个数组用于存储最终结果
        for(int i = 0 ; i < list.size(); i ++) res[i] = list.get(i); // 9. 将列表中的值复制到数组
        return res; // 10. 返回结果数组
    }
}

BM24 二叉树的中序遍历

二叉树的中序遍历_牛客题霸_牛客网
https://www.nowcoder.com/practice/0bf071c135e64ee2a027783b80bf781d?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj


import java.util.*;

public class Solution {
    void inorder(ArrayList<Integer> list, TreeNode root){ // 1. 定义中序遍历辅助方法
        if(root == null) return; // 2. 如果当前节点为空,直接返回
        inorder(list,root.left); // 3. 递归遍历左子树
        list.add(root.val); // 4. 访问当前节点,将值加入列表
        inorder(list,root.right); // 5. 递归遍历右子树
    }
    public int[] inorderTraversal (TreeNode root) {
        ArrayList<Integer> list = new ArrayList<>(); // 6. 创建一个列表用于存储遍历结果
        inorder(list,root); // 7. 调用中序遍历辅助方法
        int [] res = new int [list.size()]; // 8. 创建一个数组用于存储最终结果
        for(int i = 0 ; i < list.size() ; i ++){ // 9. 将列表中的值复制到数组
            res[i] = list.get(i);
        }
        return res; // 10. 返回结果数组
    }
}

BM25 二叉树的后序遍历

二叉树的后序遍历_牛客题霸_牛客网
https://www.nowcoder.com/practice/1291064f4d5d4bdeaefbf0dd47d78541?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page

import java.util.*;

public class Solution {
    // 1. 递归辅助函数:后序遍历子树并把节点值追加到 list
    void postorder(ArrayList<Integer> list, TreeNode root){
        if(root == null) return;          // 2. 空节点直接返回
        postorder(list,root.left);        // 3. 递归遍历左子树
        postorder(list,root.right);       // 4. 递归遍历右子树
        list.add(root.val);               // 5. 访问当前节点:将值加入 list
    }
    
    // 6. 主函数:返回整棵树的后序遍历结果(int 数组形式)
    public int[] postorderTraversal (TreeNode root) {
        ArrayList<Integer> list = new ArrayList<Integer>(); // 7. 用于存放遍历结果的动态数组
        postorder(list,root);            // 8. 调用辅助函数完成后序遍历并填充 list
        int [] res = new int[list.size()]; // 9. 创建与 list 长度相同的 int 数组
        for(int i = 0 ; i < list.size() ; i ++) 
            res[i] = list.get(i);        // 10. 将 list 中的值逐个复制到数组 res
        return res;                      // 11. 返回后序遍历结果数组
    }
}

BM26 求二叉树的层序遍历

求二叉树的层序遍历_牛客题霸_牛客网
https://www.nowcoder.com/practice/04a5560e43e24e9db4595865dc9c63a3?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page

import java.util.*;

public class Solution {
  
    public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {
        ArrayList<ArrayList<Integer>> res = new ArrayList();// 1. 创建数据来存放答案
        if(root == null) return res;// 2. 如果是空树 则返回空
        Queue<TreeNode> q = new ArrayDeque<TreeNode> ();// 3. 创建一个双端队列来遍历
        q.add(root);// 4. 初始化根节点放到队列之中
        while(!q.isEmpty()){// 5. 如果队列不是空的
            ArrayList<Integer> row = new ArrayList();// 6. 存放当前层的节点的值
            int n = q.size();// 7. 计算当前层有多少个节点
            for(int i = 0 ; i < n ; i ++){// 8. 处理当前的所有节点
                TreeNode cur = q.poll();// 9. 结点出队
                row.add(cur.val);// 10. 当前节点的答案
                if(cur.left != null) q.add(cur.left);// 11. 当前层节点的左节点入队(若有)
                if(cur.right != null) q.add(cur.right);// 12. 当前层节点的右节点入队(若有)
            }
            res.add(row);// 13. 添加答案
        }
        return res;
    }
}

BM27 按之字形顺序打印二叉树

按之字形顺序打印二叉树_牛客题霸_牛客网
https://www.nowcoder.com/practice/91b69814117f4e8097390d107d2efbe0?tpId=295&tqId=644&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page

  1. 直接利用队列 广搜
import java.util.*;

public class Solution {
 
    public ArrayList<ArrayList<Integer>> Print (TreeNode pRoot) {
        TreeNode h = pRoot;                          // 1. 用临时变量 h 保存根节点引用,避免直接修改形参
        ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>(); // 2. 创建最终结果列表 res,用于存放按层划分的节点值
        if(h == null) return res;                    // 3. 如果根节点为空,直接返回空的结果列表
        Queue<TreeNode> q = new LinkedList<TreeNode>(); // 4. 创建队列 q,用于实现广度优先(层序)遍历
        q.offer(h);                                  // 5. 将根节点加入队列,作为遍历起点
        int f = 0;                                   // 6. 初始化层号计数器 f 为 0(根节点视为第 0 层)
        while(!q.isEmpty()){                         // 7. 只要队列中还有节点,就继续循环
            ArrayList<Integer> row = new ArrayList<>(); // 8. 创建当前层的节点值列表 row
            int n = q.size();                        // 9. 获取当前层的节点数量 n(队列长度)
            for(int i = 0 ; i < n ; i ++){          // 10. 循环 n 次,处理当前层的所有节点
                TreeNode cur = q.poll();             // 11. 从队列头部取出一个节点 cur
                row.add(cur.val);                    // 12. 将当前节点的值加入 row 列表
                if(cur.left != null) q.add(cur.left); // 13. 如果 cur 有左孩子,将左孩子加入队列
                if(cur.right != null) q.add(cur.right); // 14. 如果 cur 有右孩子,将右孩子加入队列
            }
            f++;                                     // 15. 层号计数器 f 加 1,准备处理下一层
            if(f % 2 == 0) Collections.reverse(row); // 16. 如果当前层号为偶数,反转 row 列表,实现之字形输出
            res.add(row);                            // 17. 将当前层的节点值列表加入最终结果 res
        }
        return res;                                  // 18. 返回层序遍历后的之字形结果列表
    }
}
  1. 使用两个栈,利用先进后出特性来反转
import java.util.*;

public class Solution {
 
    public ArrayList<ArrayList<Integer>> Print (TreeNode pRoot) {
        TreeNode h = pRoot;                                  // 1. 用临时变量 h 保存根节点,避免直接修改形参
        ArrayList<ArrayList<Integer>> res = new ArrayList<>(); // 2. 创建最终结果容器 res
        if(h == null) return res;                            // 3. 空树直接返回空列表
        
        Stack<TreeNode> s1 = new Stack<TreeNode>();          // 4. 奇数层(从左到右)使用的栈
        Stack<TreeNode> s2 = new Stack<TreeNode>();          // 5. 偶数层(从右到左)使用的栈
        
        s1.push(h);                                          // 6. 根节点压入 s1,作为第 1 层(奇数层)
        
        while(!s1.isEmpty() || !s2.isEmpty()){               // 7. 只要任一栈非空就继续遍历
            ArrayList<Integer> row = new ArrayList<>();      // 8. 存放当前层节点值
            
            while(!s1.isEmpty()){                            // 9. 处理奇数层:s1 不为空
                TreeNode cur = s1.pop();                     // 10. 弹出栈顶节点
                row.add(cur.val);                            // 11. 记录节点值
                if(cur.left != null) s2.add(cur.left);       // 12. 左孩子先入 s2(下一层逆序用)
                if(cur.right != null) s2.add(cur.right);     // 13. 右孩子后入 s2
            }
            
            if(row.size() != 0)                              // 14. 若本层有节点
                res.add(new ArrayList<Integer>(row));        // 15. 深拷贝 row 加入到结果
            row.clear();                                     // 16. 清空 row,准备下一轮
            
            while(!s2.isEmpty()){                            // 17. 处理偶数层:s2 不为空
                TreeNode cur = s2.pop();                     // 18. 弹出栈顶节点
                row.add(cur.val);                            // 19. 记录节点值
                if(cur.right != null) s1.add(cur.right);     // 20. 右孩子先入 s1(下一层逆序用)
                if(cur.left != null) s1.add(cur.left);       // 21. 左孩子后入 s1
            }
            
            if(row.size() != 0)                              // 22. 若本层有节点
                res.add(new ArrayList<Integer>(row));        // 23. 深拷贝 row 加入到结果
            row.clear();                                     // 24. 清空 row,准备下一轮
        }
        return res;                                          // 25. 返回最终之字形层序遍历结果
    }
}

BM28 二叉树的最大深度

二叉树的最大深度_牛客题霸_牛客网
https://www.nowcoder.com/practice/8a2b2bf6c19b4f23a9bdb9b233eefa73?tpId=295&tqId=642&sourceUrl=%2Fexam%2Foj

import java.util.*;

public class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) return 0; // 1. 如果根节点为空,直接返回深度为 0
        Queue<TreeNode> q = new LinkedList<TreeNode>(); // 2. 创建一个队列用于层序遍历
        int res = 0; // 3. 初始化最大深度
        q.add(root); // 4. 将根节点加入队列
        while (!q.isEmpty()) { // 5. 当队列不为空时,继续遍历
            int size = q.size(); // 6. 获取当前层的节点数
            for (int i = 0; i < size; i++) { // 7. 遍历当前层的所有节点
                TreeNode node = q.poll(); // 8. 弹出队列中的节点
                if (node.left != null) q.add(node.left); // 9. 如果左子节点不为空,加入队列
                if (node.right != null) q.add(node.right); // 10. 如果右子节点不为空,加入队列
            }
            res++; // 11. 每遍历完一层,深度加 1
        }
        return res; // 12. 返回最大深度
    }
}

BM29 二叉树中和为某一值的路径(一)

二叉树中和为某一值的路径(一)_牛客题霸_牛客网
https://www.nowcoder.com/practice/508378c0823c423baa723ce448cbfd0c?tpId=295&tqId=634&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AC%2594%25E9%259D%25A2%25E8%25AF%2595%25E7%25AF%2587%26topicId%3D295
2025年8月13日16:38:15 2025年8月13日16:48:21

  1. 递归
import java.util.*;

public class Solution {
    public boolean hasPathSum (TreeNode root, int sum) {
        if(root == null) return false;// 1. 空节点说明之前的路径已走完,且未满足目标和,返回 false
        if(root.left == null && root.right == null && root.val == sum) return true;// 2. 到达叶子节点:若剩余值等于当前节点值,则找到一条满足条件的路径,返回 true
        // 3. 递归检查左子树和右子树,目标和减去当前节点的值
        return hasPathSum(root.left, sum - root.val)   // 4. 向左子树继续寻找
            || hasPathSum(root.right, sum - root.val); // 5. 向右子树继续寻找
    }
}
  1. 使用广搜,Pair记录从头节点到叶子的总值
import java.util.*;

public class Solution {
    // 1. 辅助类 P:同时携带节点引用与该节点到根路径上的累加和
    class P {
        TreeNode node = null;  // 2. 当前节点
        int cursum = 0;        // 3. 从根到当前节点的路径和
        public P(TreeNode node, int cursum) {
            this.node = node;  // 4. 初始化节点
            this.cursum = cursum; // 5. 初始化累加和
        }
    }

    public boolean hasPathSum (TreeNode root, int sum) {
        // 6. 空树直接返回 false
        if (root == null) return false;
        // 7. 创建队列,用于广度优先遍历
        Queue<P> q = new LinkedList<>();
        // 8. 将根节点及其值封装成 P 并入队
        P p = new P(root, root.val);
        q.add(p);
        // 9. 队列非空则继续处理
        while (!q.isEmpty()) {
            // 10. 取出队首元素
            P cur = q.poll();
            // 11. 若存在左孩子,创建新的 P 并入队
            if (cur.node.left != null) {
                q.add(
                    new P(
                        cur.node.left,                  // 12. 左孩子节点
                        cur.cursum + cur.node.left.val  // 13. 新的累加和
                    )
                );
            }
            // 14. 若存在右孩子,创建新的 P 并入队
            if (cur.node.right != null) {
                q.add(
                    new P(
                        cur.node.right,                 // 15. 右孩子节点
                        cur.cursum + cur.node.right.val // 16. 新的累加和
                    )
                );
            }
            // 17. 当前节点是叶子节点
            if (cur.node.left == null && cur.node.right == null) {
                // 18. 若累加和等于目标和,立即返回 true
                if (sum == cur.cursum) return true;
            }
        }
        // 19. 遍历结束仍未找到符合条件的路径,返回 false
        return false;
    }
}

BM30 二叉搜索树与双向链表

二叉搜索树与双向链表_牛客题霸_牛客网
https://www.nowcoder.com/practice/947f6eb80d944a84850b0538bf0ec3a5?tpId=295&tqId=23253&sourceUrl=%2Fexam%2Foj

  1. 递归中序遍历
import java.util.*;

public class Solution {
    TreeNode head = null;  // 1. 最终要返回的双向链表头结点
    TreeNode pre  = null;  // 2. 指向当前已处理部分的尾结点(上一次访问的结点)
    public TreeNode Convert(TreeNode p) {
        if (p == null) return null;// 3. 空树直接返回 null
        Convert(p.left);// 4. 递归处理左子树:把整棵左子树构造成双向链表
        if (pre == null) {// 5. 此时 pre == null 说明正在访问整棵树的最左叶子,即为链表头结点
            head = p;      // 6. 记录头结点
            pre  = p;      // 7. 当前结点成为已处理部分的尾结点
        } else {           // 8. 将当前结点 p 接到已处理链表的末尾
            pre.right = p; // 9. 尾结点的后继指向当前结点
            p.left  = pre; // 10. 当前结点的前驱指向尾结点
            pre = p;       // 11. 更新尾结点指针
        }
        Convert(p.right); // 12. 递归处理右子树:继续把右子树结点接到链表后面
        return head;// 13. 整棵树遍历完后,head 即为所求双向链表的头结点
    }
}
  1. 非递归中序遍历
import java.util.*;

public class Solution {
    public TreeNode Convert(TreeNode p) {
        if(p == null) return null;                  // 1. 空树直接返回 null
        Stack<TreeNode> s = new Stack<TreeNode>();  // 2. 创建栈,用于非递归中序遍历
        TreeNode head = null;                       // 3. 最终要返回的双向链表头结点
        TreeNode pre = null;                        // 4. 指向当前已处理链表的尾结点
        boolean isHead = true;                      // 5. 标记是否第一次访问到最左结点(即链表头结点)

        while(p != null || !s.isEmpty()){           // 6. 外层循环:当 p 非空或栈非空时继续
            while(p != null){                       // 7. 内层循环:沿左子树一路到底
                s.push(p);                          // 8. 当前结点入栈
                p = p.left;                         // 9. 继续深入左孩子
            }
            p = s.pop();                            // 10. 弹出栈顶结点(此时为最左未访问结点)
            if(isHead){                             // 11. 如果是第一次访问(最左结点)
                head = p;                           // 12. 记录头结点
                pre = p;                            // 13. 当前结点成为已处理链表的尾结点
                isHead = false;                     // 14. 标记已处理过头结点
            }else{                                  // 15. 否则,已有部分链表
                pre.right = p;                      // 16. 尾结点的后继指向当前结点
                p.left = pre;                       // 17. 当前结点的前驱指向尾结点
                pre = p;                            // 18. 更新尾结点指针
            }
            p = p.right;                            // 19. 转向当前结点的右子树(可能为空)
        }
        return head;                                // 20. 返回构造好的双向链表头结点
    }
}

BM31 对称的二叉树

对称的二叉树_牛客题霸_牛客网
https://www.nowcoder.com/practice/ff05d44dfdb04e1d83bdbdab320efbcb?tpId=295&tqId=23253&sourceUrl=%2Fexam%2Foj
2025年8月14日14:05:33 2025年8月14日14:22:40

  1. 层序遍历 + 回文/对称
import java.util.*;

public class Solution {
    int INF = 0x3f3f3f;                       // 1. 用一个极大值作为空节点的占位值
    TreeNode emptyNode = new TreeNode(INF);   // 2. 创建统一的空节点对象,用于缺失左右孩子时的占位
    // 3. 检查给定层序列表是否为回文(对称)
    boolean check(ArrayList<Integer> list){
        int n = list.size();                  // 4. 当前层节点个数
        for(int i = 0 ; i < n ; i ++){        // 5. 双指针对撞比较
            if(!list.get(i).equals(list.get(n - 1 - i))) return false; // 6. 发现不对称立即返回 false
        }
        return true;                          // 7. 全部对称则返回 true
    }
    public boolean isSymmetrical (TreeNode p) {
        if(p == null) return true;            // 8. 空树视为对称,直接返回 true
        Queue<TreeNode> q = new LinkedList<>(); // 9. 队列用于层序(广度优先)遍历
        q.offer(p);                           // 10. 根节点入队
        while(!q.isEmpty()){                  // 11. 逐层处理直到队列为空
            int n = q.size();                 // 12. 当前层的节点数量
            ArrayList<Integer> row = new ArrayList<>(); // 13. 存放当前层的值(含占位值)
            for(int i = 0; i < n ; i ++){     // 14. 处理当前层的所有节点
                TreeNode cur = q.poll();      // 15. 取出队首节点
                if(!cur.equals(emptyNode)){   // 16. 若非空节点
                    // 17. 左孩子存在则入队真实节点,否则入队空节点占位
                    q.add(cur.left != null ? cur.left : emptyNode);
                    // 18. 右孩子存在则入队真实节点,否则入队空节点占位
                    q.add(cur.right != null ? cur.right : emptyNode);
                }
                row.add(cur.val);             // 19. 记录当前节点值(含占位值)
            }
            // 20. 只要某层不对称,整棵树就不对称
            if(!check(row)) return false;
        }
        return true;                          // 21. 所有层都对称,返回 true
    }
}
  1. 递归写法
import java.util.*;

public class Solution {
    // 1. 辅助函数:递归判断以 p1、p2 为根的两棵子树是否镜像对称
    boolean chk(TreeNode p1, TreeNode p2) {
        // 2. 两棵树同时为空 → 对称
        if (p1 == null && p2 == null) return true;
        // 3. 仅有一棵为空 → 不对称
        if (p1 == null || p2 == null) return false;
        // 4. 节点值不相等 → 不对称
        if (p1.val != p2.val) return false;
        // 5. 递归检查:p1 的左子树与 p2 的右子树、p1 的右子树与 p2 的左子树是否都镜像对称
        return chk(p1.left, p2.right) && chk(p1.right, p2.left);
    }

    public boolean isSymmetrical (TreeNode p) {
        // 6. 以整棵树的根节点同时作为左、右子树,调用 chk 判断整体是否对称
        return chk(p, p);
    }
}

BM32 合并二叉树

合并二叉树_牛客题霸_牛客网
https://www.nowcoder.com/practice/7298353c24cc42e3bd5f0e0bd3d1d759?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj

import java.util.*;

public class Solution {

    public TreeNode mergeTrees (TreeNode t1, TreeNode t2) {
        // 1. 如果 t1 为空,直接返回 t2 作为合并结果
        if (t1 == null) return t2;
        // 2. 如果 t2 为空,直接返回 t1 作为合并结果
        if (t2 == null) return t1;

        // 3. 新建节点 head,其值为 t1 与 t2 节点值之和
        TreeNode head = new TreeNode(t1.val + t2.val);

        // 4. 递归合并 t1 与 t2 的左子树,结果挂到 head.left
        head.left = mergeTrees(t1.left, t2.left);

        // 5. 递归合并 t1 与 t2 的右子树,结果挂到 head.right
        head.right = mergeTrees(t1.right, t2.right);

        // 6. 返回合并后的根节点
        return head;
    }
}

BM33 二叉树的镜像

二叉树的镜像_牛客题霸_牛客网
https://www.nowcoder.com/practice/a9d0ecbacef9410ca97463e4a5c83be7?tpId=295&tqId=1374963&sourceUrl=%2Fexam%2Foj

  1. 直接递归
import java.util.*;

public class Solution {
    public TreeNode Mirror (TreeNode p) {
       if (p == null) return null; // 1. 若当前节点为空,直接返回 null
        TreeNode left = Mirror(p.left);// 2. 递归翻转左子树,得到翻转后的左子树(此时已变成右子树)
        TreeNode right = Mirror(p.right);// 3. 递归翻转右子树,得到翻转后的右子树(此时已变成左子树)
        p.left = right;// 4. 将当前节点的左指针指向翻转后的右子树
        p.right = left;// 5. 将当前节点的右指针指向翻转后的左子树
        return p;        // 6. 返回已完成翻转的当前节点
    }
}
  1. 借助辅助空间,栈
import java.util.*;

public class Solution {
    public TreeNode Mirror (TreeNode p) {
        if (p == null) return null;         // 1. 空树直接返回
        Stack<TreeNode> s = new Stack<TreeNode>();  // 2. 创建栈用于迭代
        s.push(p);                          // 3. 根节点入栈
        while (!s.isEmpty()) {              // 4. 栈非空则继续处理
            TreeNode cur = s.pop();         // 5. 弹出当前待处理节点
            if (cur.left != null) s.push(cur.left); // 6. 左孩子入栈
            if (cur.right != null) s.push(cur.right); // 7. 右孩子入栈
            TreeNode temp = cur.left;       // 8. 暂存原左子树
            cur.left = cur.right;           // 9. 左指针指向原右子树
            cur.right = temp;               // 10. 右指针指向原左子树
        }
        return p;                           // 11. 返回翻转后的根节点
    }
}

BM34 判断是不是二叉搜索树

判断是不是二叉搜索树_牛客题霸_牛客网
https://www.nowcoder.com/practice/a69242b39baf45dea217815c7dedb52b?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj

  1. 栈模拟,然后中序遍历是否单调
import java.util.*;

public class Solution {
    public boolean isValidBST (TreeNode root) {
        if (root == null) return true;                     // 1. 空树视为合法 BST
        Stack<TreeNode> s = new Stack<TreeNode>();         // 2. 创建栈,用于中序遍历
        ArrayList<Integer> list = new ArrayList<Integer>();// 3. 存放中序遍历得到的节点值
        TreeNode head = root;                              // 4. 当前遍历指针,初始指向根节点
        while (head != null || !s.isEmpty()) {             // 5. 只要指针非空或栈非空就继续
            while (head != null) {                         // 6. 一路向左走到头
                s.push(head);                              // 7. 沿途节点入栈
                head = head.left;                          // 8. 继续深入左子树
            }
            head = s.pop();                                // 9. 弹出栈顶(最左未访问节点)
            list.add(head.val);                            // 10. 记录节点值
            head = head.right;                             // 11. 转向右子树
        }
        for (int i = 1; i < list.size(); i++) { // 12. 检查中序序列是否严格递增
            if (list.get(i) <= list.get(i - 1)) return false; // 13. 出现非递增即非 BST
        }
        return true;                                       // 14. 全部递增,是合法 BST
    }
}
  1. 递归
import java.util.*;

public class Solution {
    int pre = Integer.MIN_VALUE;        // 1 保存前一个节点的值,初始化为整型最小值
    public boolean isValidBST (TreeNode root) {
       if(root == null) return true;    // 2 空树被认为是合法的 BST
       if(!isValidBST(root.left)) return false; // 3 先递归检查左子树是否合法
       if(root.val < pre) return false; // 4 若当前节点值不大于前一个节点值,则违反 BST 性质
       pre = root.val;                 // 5 更新 pre 为当前节点值,准备与下一个节点比较
       return isValidBST(root.right);  // 6 最后递归检查右子树是否合法
    }
}

BM35 判断是不是完全二叉树

判断是不是完全二叉树_牛客题霸_牛客网
https://www.nowcoder.com/practice/8daa4dff9e36409abba2adbe413d6fae?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj

import java.util.*;

public class Solution {
    public boolean isCompleteTree (TreeNode root) {
        if(root == null) return true;                // 1 空树视为完全二叉树
        Queue<TreeNode> q = new LinkedList<TreeNode>(); // 2 创建队列用于层序遍历
        q.offer(root);                               // 3 根节点入队
        boolean notOk = false;                       // 4 标记是否已遇到空节点
        while(!q.isEmpty()){                         // 5 队列非空时循环
            TreeNode cur = q.poll();                 // 6 取出队首节点
            if(cur == null) {                        // 7 遇到空节点
                notOk = true;                        // 8 置位标记
                continue;                            // 9 继续处理后续节点
            }
            if(notOk) return false;                  // 10 若之前已遇到空节点且当前节点非空,则不完整
            q.offer(cur.left);                       // 11 左孩子入队(可为 null)
            q.offer(cur.right);                      // 12 右孩子入队(可为 null)
        }
        return true;                                 // 13 全部遍历完未发现违规,返回 true
    }
}

BM36 判断是不是平衡二叉树

判断是不是平衡二叉树_牛客题霸_牛客网
https://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj

import java.util.*;

public class Solution {
    boolean isOk = true;                         // 1 全局标志,记录整棵树是否平衡
    public int depth(TreeNode p){                // 2 后序遍历求当前子树高度
        if(p == null){                           // 3 空节点高度为 0
            return 0;
        }
        int l = depth(p.left);                   // 4 递归获取左子树高度
        int r = depth(p.right);                  // 5 递归获取右子树高度
        if(Math.abs(l - r) > 1){                 // 6 左右高度差超过 1,则不平衡
            isOk = false;
        }
        return Math.max(l, r) + 1;               // 7 返回当前子树高度
    }
    public boolean IsBalanced_Solution (TreeNode pRoot) {
        int d = depth(pRoot);                    // 8 触发整棵树的遍历与标记
        return isOk;                             // 9 返回是否平衡的最终结果
    }
}
  1. 方法一 剪枝
import java.util.*;

public class Solution {
    boolean isOk = true;                // 1 全局标志,标记整棵树是否平衡
    public int depth(TreeNode p){       // 2 后序遍历求子树高度,不平衡时直接返回-1剪枝
        if(p == null){                  // 3 空节点高度为0
            return 0;
        }
        int l = depth(p.left);          // 4 递归求左子树高度
        if(l == -1) return -1;          // 5 左子树不平衡,向上传递-1
        int r = depth(p.right);         // 6 递归求右子树高度
        if(r == -1) return -1;          // 7 右子树不平衡,向上传递-1
        if(Math.abs(l - r) > 1){        // 8 左右高度差大于1,当前子树不平衡
            isOk = false;               // 9 置位全局不平衡标志
            return -1;                  // 10 向上返回-1表示不平衡
        }
        return Math.max(l, r) + 1;      // 11 当前子树平衡,返回其高度
    }
    public boolean IsBalanced_Solution (TreeNode pRoot) {
        int d = depth(pRoot);           // 12 触发整棵树的后序遍历与剪枝检查
        return isOk;                    // 13 返回最终是否平衡的结果
    }
}

BM37 二叉搜索树的最近公共祖先

二叉搜索树的最近公共祖先_牛客题霸_牛客网
https://www.nowcoder.com/practice/d9820119321945f588ed6a26f0a6991f?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj

  1. 遍历两个节点的路径
import java.util.*;

public class Solution {
    ArrayList<Integer> getPath(TreeNode r, int n){
        ArrayList<Integer> res = new ArrayList<Integer>(); // 1. 创建结果列表,存储路径上的节点值
        TreeNode p = r; // 2. 从根节点开始
        while(p.val != n){ // 3. 遍历二叉搜索树,直到找到目标节点 n
            res.add(p.val); // 4. 将当前节点值加入路径
            if(n < p.val){ // 5. 如果目标值小于当前节点值,向左子树移动
                p = p.left;
            }else { // 6. 如果目标值大于当前节点值,向右子树移动
                p = p.right;
            }
        }  
        res.add(p.val); // 7. 将目标节点值加入路径
        return res; // 8. 返回完整的路径
    }
    public int lowestCommonAncestor (TreeNode r, int p, int q) {
        ArrayList<Integer> ppath = getPath(r,p); // 9. 获取从根节点到节点 p 的路径
        ArrayList<Integer> qpath = getPath(r,q); // 10. 获取从根节点到节点 q 的路径
        int ans = 0; // 11. 初始化最低公共祖先的值
        for(int i = 0 ; i  < ppath.size() && i < qpath.size(); i ++){ // 12. 遍历两条路径,找到最后一个相同的节点
            int x = ppath.get(i); // 13. 获取路径 p 中的当前节点值
            int y = qpath.get(i); // 14. 获取路径 q 中的当前节点值
            if(x == y) ans = ppath.get(i); // 15. 如果两个值相同,更新最低公共祖先
            else break; // 16. 如果不同,停止遍历
        }
        return ans; // 17. 返回最低公共祖先的值
    }
}
  1. 用一个set存 遍历到最后一个一样的节点
import java.util.*;

public class Solution {
    public int lowestCommonAncestor (TreeNode r, int p, int q) {
        Set<Integer> s = new HashSet<Integer>(); // 1. 创建一个集合,用于存储从根节点到节点 p 的路径上的节点值
        TreeNode cur = r; // 2. 从根节点开始
        while(cur.val != p){ // 3. 遍历二叉搜索树,直到找到节点 p
            s.add(cur.val); // 4. 将当前节点值加入集合
            if(cur.val > p) cur = cur.left; // 5. 如果当前节点值大于 p,向左子树移动
            else cur = cur.right; // 6. 如果当前节点值小于 p,向右子树移动
        }
        s.add(cur.val); // 7. 将节点 p 的值加入集合
        cur = r; // 8. 重新从根节点开始
        int res = -1; // 9. 初始化最低公共祖先的值为 -1
        while(cur.val != q){ // 10. 遍历二叉搜索树,直到找到节点 q
            if(s.contains(cur.val)) res = cur.val; // 11. 如果当前节点值在集合中,更新最低公共祖先
            if(cur.val > q) cur = cur.left; // 12. 如果当前节点值大于 q,向左子树移动
            else cur = cur.right; // 13. 如果当前节点值小于 q,向右子树移动
        }
        return res == -1 ? q : res; // 14. 如果 res 仍为 -1,说明 q 本身就是最低公共祖先,否则返回 res
    }
}

BM38 在二叉树中找到两个节点的最近公共祖先

在二叉树中找到两个节点的最近公共祖先_牛客题霸_牛客网
https://www.nowcoder.com/practice/e0cc33a83afe4530bcec46eba3325116?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj

  1. dfs + 路径比较
import java.util.*;

public class Solution {
    boolean ok = false; // 剪枝标记
    void depth(TreeNode p,int t,ArrayList<Integer> cur){
        if(p == null || ok) return; // 1. 如果当前节点为空或已找到目标节点,直接返回
        cur.add(p.val); // 2. 将当前节点值加入路径
        if(p.val == t){ // 3. 如果当前节点值等于目标值 t
            ok = true; // 4. 标记找到目标节点
            return;
        }
        depth(p.left,t,cur); // 5. 递归遍历左子树
        depth(p.right,t,cur); // 6. 递归遍历右子树
        if(ok) return; // 7. 如果已找到目标节点,直接返回
        cur.remove(cur.size() - 1); // 8. 回溯,移除当前节点值
    }
    public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
        ArrayList<Integer> l1 = new ArrayList<Integer>(); // 9. 存储从根节点到 o1 的路径
        ArrayList<Integer> l2 = new ArrayList<Integer>(); // 10. 存储从根节点到 o2 的路径
        ok = false; // 11. 重置标志变量
        depth(root,o1,l1); // 12. 获取从根节点到 o1 的路径
        ok = false; // 13. 重置标志变量
        depth(root,o2,l2); // 14. 获取从根节点到 o2 的路径

        int res = 0; // 15. 初始化最低公共祖先的值
        for(int i = 0 ; i < l1.size() && i < l2.size(); i ++){ // 16. 遍历两条路径,找到最后一个相同的节点
            if(l1.get(i).equals(l2.get(i))) res = l1.get(i); // 17. 如果两个路径上的节点值相同,更新最低公共祖先
            else break; // 18. 如果不同,停止遍历
        }
        return res; // 19. 返回最低公共祖先的值
    }
}
  1. 递归
import java.util.*;

public class Solution {
    public int lowestCommonAncestor(TreeNode r, int o1, int o2) {
        if (r == null) return -1; // 1. 如果当前节点为空,返回 -1 表示未找到
        if (r.val == o1 || r.val == o2) return r.val;// 2. 如果当前节点值等于 o1 或 o2,返回当前节点值
        int lf = lowestCommonAncestor(r.left, o1, o2); // 3. 递归在左子树中查找最低公共祖先
        int rh = lowestCommonAncestor(r.right, o1, o2); // 4. 递归在右子树中查找最低公共祖先
        if (lf == -1) return rh; // 5. 如果左子树未找到,返回右子树的结果
        if (rh == -1) return lf; // 6. 如果右子树未找到,返回左子树的结果
        return r.val; // 7. 如果左右子树都找到了,当前节点就是最低公共祖先
    }
}

BM39 序列化二叉树

序列化二叉树_牛客题霸_牛客网
https://www.nowcoder.com/practice/cf7e25aa97c04cc1a68c8f040e71fb84?tpId=295&tqId=23455&sourceUrl=%2Fexam%2Foj

  1. 广搜遍历 + StringBuilder
import java.util.*;

public class Solution {
    int INF = Integer.MAX_VALUE; // 1. 定义一个无穷大值,用于标记空节点
    TreeNode emptyNode = new TreeNode(INF); // 2. 创建一个值为 INF 的空节点

    // 3. 序列化二叉树
    String Serialize(TreeNode r) {
        if (r == null) return ""; // 4. 如果根节点为空,返回空字符串
        StringBuilder sb = new StringBuilder(); // 5. 创建一个字符串构建器用于存储序列化结果
        Deque<TreeNode> dq = new ArrayDeque<>(); // 6. 创建一个双端队列用于层序遍历
        dq.addLast(r); // 7. 将根节点加入队列
        while (!dq.isEmpty()) { // 8. 遍历队列直到为空
            TreeNode cur = dq.pollFirst(); // 9. 取出队首节点
            sb.append(cur.val + "_"); // 10. 将当前节点值追加到字符串构建器
            if (!cur.equals(emptyNode)) { // 11. 如果当前节点不是空节点
                dq.addLast(cur.left != null ? cur.left : emptyNode); // 12. 将左子节点加入队列(若为空则加入空节点)
                dq.addLast(cur.right != null ? cur.right : emptyNode); // 13. 将右子节点加入队列(若为空则加入空节点)
            }
        }
        return sb.toString(); // 14. 返回序列化后的字符串
    }

    // 15. 反序列化二叉树
    TreeNode Deserialize(String str) {
        if (str.equals("")) return null; // 16. 如果字符串为空,返回空节点
        String[] s = str.split("_"); // 17. 将字符串按 "_" 分割成数组
        int n = s.length; // 18. 获取数组长度
        TreeNode p = new TreeNode(Integer.parseInt(s[0])); // 19. 创建根节点
        Deque<TreeNode> dq = new ArrayDeque<TreeNode>(); // 20. 创建一个双端队列用于层序遍历
        dq.addLast(p); // 21. 将根节点加入队列
        for (int i = 1; i < n - 1; i += 2) { // 22. 遍历数组,每次处理两个子节点
            TreeNode cur = dq.pollFirst(); // 23. 取出队首节点
            int l = Integer.parseInt(s[i]), r = Integer.parseInt(s[i + 1]); // 24. 获取左右子节点的值
            if (l != INF) { // 25. 如果左子节点值不是 INF
                cur.left = new TreeNode(l); // 26. 创建左子节点
                dq.addLast(cur.left); // 27. 将左子节点加入队列
            }
            if (r != INF) { // 28. 如果右子节点值不是 INF
                cur.right = new TreeNode(r); // 29. 创建右子节点
                dq.addLast(cur.right); // 30. 将右子节点加入队列
            }
        }
        return p; // 31. 返回重建的二叉树根节点
    }
}
  1. 递归
import java.util.*;

public class Solution {
    static int idx = 0; // 1. 静态变量,用于记录反序列化时的字符串索引位置

    // 2. 序列化辅助函数,递归地将二叉树序列化为字符串
    void SerializeFuction(TreeNode p, StringBuilder sb) {
        if (p == null) { // 3. 如果当前节点为空,追加 '#' 表示空节点
            sb.append('#');
            return;
        }
        sb.append(p.val).append("_"); // 4. 将当前节点值追加到字符串构建器,并添加分隔符 "_"
        SerializeFuction(p.left, sb); // 5. 递归序列化左子树
        SerializeFuction(p.right, sb); // 6. 递归序列化右子树
    }

    // 7. 序列化主函数,调用辅助函数完成序列化
    String Serialize(TreeNode r) {
        if (r == null) return "#"; // 8. 如果根节点为空,返回特殊字符 "#" 表示空树
        StringBuilder res = new StringBuilder(); // 9. 创建字符串构建器用于存储序列化结果
        SerializeFuction(r, res); // 10. 调用辅助函数进行序列化
        return res.toString(); // 11. 返回序列化后的字符串
    }

    // 12. 反序列化辅助函数,递归地从字符串中重建二叉树
    TreeNode DeserializeFuction(String str) {
        if (str.charAt(idx) == '#') { // 13. 如果当前字符是 '#',表示空节点
            idx++; // 14. 索引后移
            return null;
        }
        int val = 0; // 15. 初始化节点值
        // 16. 解析当前节点的值,直到遇到分隔符 "_" 或字符串结束
        while (str.charAt(idx) != '_' && idx != str.length()) {
            val = val * 10 + (str.charAt(idx) - '0'); // 17. 将字符转换为数字并累加
            idx++; // 18. 索引后移
        }
        TreeNode p = new TreeNode(val); // 19. 创建当前节点
        if (idx == str.length()) return p; // 20. 如果已到达字符串末尾,返回当前节点
        else idx++; // 21. 跳过分隔符 "_"
        p.left = DeserializeFuction(str); // 22. 递归重建左子树
        p.right = DeserializeFuction(str); // 23. 递归重建右子树
        return p; // 24. 返回重建的当前节点
    }

    // 25. 反序列化主函数,调用辅助函数完成反序列化
    TreeNode Deserialize(String str) {
        if (str.equals("#")) return null; // 26. 如果字符串为 "#",返回空节点
        idx = 0; // 27. 重置索引
        TreeNode res = DeserializeFuction(str); // 28. 调用辅助函数进行反序列化
        return res; // 29. 返回重建的二叉树根节点
    }
}

BM40 重建二叉树

重建二叉树_牛客题霸_牛客网
https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj

  1. 递归
import java.util.*;

public class Solution {
    public TreeNode reConstructBinaryTree(int[] pre, int[] vin) {
        int n = pre.length; // 1. 获取前序遍历数组的长度
        int m = vin.length; // 2. 获取中序遍历数组的长度
        if (n == 0 || m == 0) return null; // 3. 如果数组长度为 0,返回空节点

        TreeNode r = new TreeNode(pre[0]); // 4. 根据前序遍历的第一个元素创建根节点
        for (int i = 0; i < vin.length; i++) { // 5. 在中序遍历数组中找到根节点的位置
            if (pre[0] == vin[i]) {
                // 6. 递归重建左子树,使用前序遍历的 [1, i+1] 和中序遍历的 [0, i]
                r.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i + 1), Arrays.copyOfRange(vin, 0, i));
                // 7. 递归重建右子树,使用前序遍历的 [i+1, n] 和中序遍历的 [i+1, m]
                r.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1, n), Arrays.copyOfRange(vin, i + 1, m));
                break; // 8. 找到根节点后退出循环
            }
        }
        return r; // 9. 返回重建的二叉树根节点
    }
}
  1. 栈遍历
import java.util.*;

public class Solution {
    public TreeNode reConstructBinaryTree(int[] pre, int[] vin) {
        int n = pre.length; // 1. 获取前序遍历数组的长度
        int m = pre.length; // 2. 获取中序遍历数组的长度
        if (n == 0 || m == 0) return null; // 3. 如果数组长度为 0,返回空节点

        Stack<TreeNode> s = new Stack<TreeNode>(); // 4. 创建一个栈,用于辅助重建二叉树
        TreeNode r = new TreeNode(pre[0]); // 5. 根据前序遍历的第一个元素创建根节点
        TreeNode cur = r; // 6. 当前节点指针初始化为根节点
        for (int i = 1, j = 0; i < n; i++) { // 7. 遍历前序遍历数组,从第二个元素开始
            if (cur.val != vin[j]) { // 8. 如果当前节点不是中序遍历中的当前节点
                cur.left = new TreeNode(pre[i]); // 9. 创建左子节点
                s.push(cur); // 10. 将当前节点压入栈
                cur = cur.left; // 11. 将当前节点指针移动到左子节点
            } else { // 12. 如果当前节点是中序遍历中的当前节点
                j++; // 13. 中序遍历指针后移
                while (!s.isEmpty() && s.peek().val == vin[j]) { // 14. 弹出栈中所有匹配的节点
                    cur = s.pop(); // 15. 更新当前节点指针
                    j++; // 16. 中序遍历指针后移
                }
                cur.right = new TreeNode(pre[i]); // 17. 创建右子节点
                cur = cur.right; // 18. 将当前节点指针移动到右子节点
            }
        }
        return r; // 19. 返回重建的二叉树根节点
    }
}

BM41 输出二叉树的右视图

输出二叉树的右视图_牛客题霸_牛客网
https://www.nowcoder.com/practice/c9480213597e45f4807880c763ddd5f0?tpId=295&tqId=1073834&sourceUrl=%2Fexam%2Foj

  1. 递归建树 , 一个哈希表维护最深节点,两个栈分别维护节点和深度
import java.util.*;

public class Solution {
    // 1. 根据前序和中序遍历结果重建二叉树
    TreeNode buildTree(int[] pre, int[] in, int preStart, int preEnd, int inStart, int inEnd) {
        if (preStart > preEnd || inStart > inEnd) return null; // 2. 如果索引范围无效,返回空节点
        TreeNode p = new TreeNode(pre[preStart]); // 3. 根据前序遍历的第一个元素创建根节点
        int idx = inStart; // 4. 初始化中序遍历中根节点的索引
        while (idx <= inEnd && in[idx] != pre[preStart]) idx++; // 5. 在中序遍历中找到根节点的位置
        int leftSize = idx - inStart; // 6. 计算左子树的大小
        // 7. 递归构建左子树
        p.left = buildTree(pre, in, preStart + 1, preStart + leftSize, inStart, idx - 1);
        // 8. 递归构建右子树
        p.right = buildTree(pre, in, preStart + leftSize + 1, preEnd, idx + 1, inEnd);
        return p; // 9. 返回重建的子树根节点
    }

    // 10. 获取二叉树的右侧视图
    ArrayList<Integer> rightSideView(TreeNode r) {
        ArrayList<Integer> res = new ArrayList<>(); // 11. 存储结果
        if (r == null) return res; // 12. 如果根节点为空,返回空列表
        Queue<TreeNode> q = new LinkedList<>(); // 13. 使用队列实现广度优先搜索
        q.add(r); // 14. 将根节点入队
        while (!q.isEmpty()) { // 15. 遍历队列直到为空
            int size = q.size(); // 16. 获取当前层的节点数
            for (int i = 0; i < size; i++) { // 17. 遍历当前层的所有节点
                TreeNode cur = q.poll(); // 18. 弹出队首节点
                if (i == size - 1) { // 19. 如果是当前层的最后一个节点
                    res.add(cur.val); // 20. 添加到结果列表
                }
                if (cur.left != null) q.add(cur.left); // 21. 左子节点入队
                if (cur.right != null) q.add(cur.right); // 22. 右子节点入队
            }
        }
        return res; // 23. 返回结果
    }

    // 24. 主函数,根据前序和中序遍历结果,返回右侧视图
    public int[] solve(int[] pre, int[] in) {
        int n = pre.length; // 25. 前序遍历数组长度
        int m = in.length; // 26. 中序遍历数组长度
        if (m == 0 || n == 0) return new int[0]; // 27. 如果数组为空,返回空数组
        TreeNode r = buildTree(pre, in, 0, n - 1, 0, m - 1); // 28. 重建二叉树
        ArrayList<Integer> tmp = rightSideView(r); // 29. 获取右侧视图
        int[] res = new int[tmp.size()]; // 30. 转换为数组
        for (int i = 0; i < tmp.size(); i++) res[i] = tmp.get(i); // 31. 填充数组
        return res; // 32. 返回结果
    }
}
  1. 库函数
import java.util.*;

public class Solution {
    // 1. 根据前序和中序遍历结果重建二叉树
    TreeNode buildTree(int[] pre, int l1, int r1, int[] in, int l2, int r2) {
        if (l1 > r1 || l2 > r2) return null; // 2. 如果索引范围无效,返回空节点
        TreeNode p = new TreeNode(pre[l1]); // 3. 根据前序遍历的第一个节点创建根节点
        int idx = 0; // 4. 初始化中序遍历中根节点的索引
        for (int i = l2; i <= r2; i++) { // 5. 在中序遍历中找到根节点的位置
            if (in[i] == pre[l1]) {
                idx = i; // 6. 记录根节点的索引
                break;
            }
        }
        int lsize = idx - l2; // 7. 计算左子树的大小
        int rsize = r2 - idx; // 8. 计算右子树的大小
        // 9. 递归构建左子树
        p.left = buildTree(pre, l1 + 1, l1 + lsize, in, l2, l2 + lsize - 1);
        // 10. 递归构建右子树
        p.right = buildTree(pre, r1 - rsize + 1, r1, in, idx + 1, r2);
        return p; // 11. 返回重建的子树根节点
    }

    // 12. 获取二叉树的右侧视图
    ArrayList<Integer> rightSideView(TreeNode r) {
        Map<Integer, Integer> mp = new HashMap<Integer, Integer>(); // 13. 用于存储每层最右侧的节点值
        int maxdepth = -1; // 14. 记录最大深度
        Stack<TreeNode> s1 = new Stack<TreeNode>(); // 15. 存储节点的栈
        Stack<Integer> s2 = new Stack<Integer>(); // 16. 存储节点深度的栈
        s1.push(r); // 17. 将根节点入栈
        s2.push(0); // 18. 根节点深度为 0
        while (!s1.isEmpty()) { // 19. 遍历栈直到为空
            TreeNode cur = s1.pop(); // 20. 弹出当前节点
            int curdepth = s2.pop(); // 21. 弹出当前节点深度
            if (cur != null) {
                maxdepth = Math.max(maxdepth, curdepth); // 22. 更新最大深度
                if (mp.get(curdepth) == null) { // 23. 如果当前深度没有记录节点值
                    mp.put(curdepth, cur.val); // 24. 记录当前节点值
                }
                s1.push(cur.left); // 25. 左子节点入栈
                s1.push(cur.right); // 26. 右子节点入栈
                s2.push(curdepth + 1); // 27. 左子节点深度 +1
                s2.push(curdepth + 1); // 28. 右子节点深度 +1
            }
        }
        ArrayList<Integer> res = new ArrayList<>(); // 29. 存储结果
        for (int i = 0; i <= maxdepth; i++) { // 30. 按深度顺序添加节点值
            res.add(mp.get(i));
        }
        return res; // 31. 返回结果
    }

    // 32. 主函数,根据前序和中序遍历结果,返回右侧视图
    public int[] solve(int[] pre, int[] in) {
        int n = pre.length; // 33. 前序遍历数组长度
        int m = in.length; // 34. 中序遍历数组长度
        if (m == 0 || n == 0) return new int[0]; // 35. 如果数组为空,返回空数组
        TreeNode r = buildTree(pre, 0, n - 1, in, 0, m - 1); // 36. 重建二叉树
        ArrayList<Integer> tmp = rightSideView(r); // 37. 获取右侧视图
        int[] res = new int[tmp.size()]; // 38. 转换为数组
        for (int i = 0; i < tmp.size(); i++) res[i] = tmp.get(i); // 39. 填充数组
        return res; // 40. 返回结果
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值