二叉树
| 题号 | 题目名称 | 核心思路 | 时间复杂度 | 空间复杂度 | 代码亮点 | 牛客原题链接 |
|---|---|---|---|---|---|---|
| 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) | 递归方法中使用全局变量 head 和 pre,非递归方法使用栈 | 🔗 直达 |
| 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) | 使用辅助函数 SerializeFuction 和 DeserializeFuction | 🔗 直达 |
| 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
- 直接利用队列 广搜
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. 返回层序遍历后的之字形结果列表
}
}
- 使用两个栈,利用先进后出特性来反转
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
- 递归
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. 向右子树继续寻找
}
}
- 使用广搜,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
- 递归中序遍历
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 即为所求双向链表的头结点
}
}
- 非递归中序遍历
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
- 层序遍历 + 回文/对称
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
}
}
- 递归写法
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
- 直接递归
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. 返回已完成翻转的当前节点
}
}
- 借助辅助空间,栈
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
- 栈模拟,然后中序遍历是否单调
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
}
}
- 递归
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 返回是否平衡的最终结果
}
}
- 方法一 剪枝
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
- 遍历两个节点的路径
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. 返回最低公共祖先的值
}
}
- 用一个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
- 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. 返回最低公共祖先的值
}
}
- 递归
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
- 广搜遍历 + 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. 返回重建的二叉树根节点
}
}
- 递归
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
- 递归
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. 返回重建的二叉树根节点
}
}
- 栈遍历
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
- 递归建树 , 一个哈希表维护最深节点,两个栈分别维护节点和深度
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. 返回结果
}
}
- 库函数
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. 返回结果
}
}
1999

被折叠的 条评论
为什么被折叠?



