目录
[🎯 题目要求](#🎯 题目要求)
[💡 超简单思路](#💡 超简单思路)
[✅ 完整解题代码](#✅ 完整解题代码)
[📝 小白通俗解析](#📝 小白通俗解析)
[🎯 题目要求](#🎯 题目要求)
[💡 核心思路(小白秒懂)](#💡 核心思路(小白秒懂))
[✅ 完整解题代码](#✅ 完整解题代码)
[📝 小白通俗解析](#📝 小白通俗解析)
[🎉 两道题终极口诀(秒记)](#🎉 两道题终极口诀(秒记))
[前序 + 中序还原二叉树](#前序 + 中序还原二叉树)
[🌟 总结](#🌟 总结)
一、二叉树展开为链表(前序遍历秒杀)
🎯 题目要求
给定一个二叉树,将它展开成一个 **"单链表"**,要求:
- 展开后的链表使用原树节点
- 所有节点的左孩子为 null
- 右孩子指向下一个节点
- 顺序与前序遍历一致
💡 超简单思路
- 前序遍历二叉树,把所有节点按顺序存到集合里
- 遍历集合,把前一个节点的左孩子置空 ,右孩子指向后一个节点
- 链表拼接完成!
✅ 完整解题代码
java
运行
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
// 存储前序遍历的所有节点
private List<TreeNode> list = new ArrayList<>();
public void flatten(TreeNode root) {
if(root == null) return;
// 1. 前序遍历收集所有节点
travle(root);
// 2. 拼接成单向链表
for(int i = 0; i < list.size() - 1; i++){
TreeNode pre = list.get(i);
TreeNode cur = list.get(i+1);
// 左孩子置空
pre.left = null;
// 右孩子指向下一个节点
pre.right = cur;
}
}
// 前序遍历:根 → 左 → 右
public void travle(TreeNode node) {
if(node == null) return;
// 先收集当前节点
list.add(node);
// 遍历左子树
travle(node.left);
// 遍历右子树
travle(node.right);
}
}
📝 小白通俗解析
- 前序遍历 = 根节点先加入,再遍历左右子树
- 用集合保存所有节点后,直接按顺序拼接
- 左边全部清空,右边连成一条线,就是题目要求的链表
- 代码短短几行,逻辑一目了然,面试写这个最快最稳!
二、从前序与中序遍历序列构造二叉树(递归分治经典)
🎯 题目要求
给定二叉树的前序遍历 和中序遍历数组,还原出这棵二叉树。
💡 核心思路(小白秒懂)
- 前序遍历第一个节点 = 整棵树的根节点
- 在中序遍历 中找到根节点位置
- 根节点左边 = 左子树
- 根节点右边 = 右子树
- 用递归分治,不断切割数组,重复找根→建节点→分左右子树
- 用 Map 记录中序遍历值与下标,快速找根节点位置
✅ 完整解题代码
java
运行
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
// 记录中序数组:值 → 下标,快速定位根节点
private Map<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
// 把中序数组存入map
for(int i = 0; i < inorder.length; i++){
map.put(inorder[i], i);
}
// 递归建树(左闭右开区间)
return find(preorder, 0, preorder.length,
inorder, 0, inorder.length);
}
// 递归分治建树
public TreeNode find(int[] preorder, int preorderBegin, int preorderEnd,
int[] inorder, int inorderBegin, int inorderEnd){
// 递归终止条件:区间无效
if(preorderBegin >= preorderEnd || inorderBegin >= inorderEnd){
return null;
}
// 前序第一个节点 = 根节点
int rootVal = preorder[preorderBegin];
// 找到根节点在中序数组中的位置
int rootIndex = map.get(rootVal);
TreeNode root = new TreeNode(rootVal);
// 左子树节点个数
int leftSize = rootIndex - inorderBegin;
// 递归构建左子树
root.left = find(preorder, preorderBegin + 1, preorderBegin + 1 + leftSize,
inorder, inorderBegin, rootIndex);
// 递归构建右子树
root.right = find(preorder, preorderBegin + 1 + leftSize, preorderEnd,
inorder, rootIndex + 1, inorderEnd);
return root;
}
}
📝 小白通俗解析
- 前序找根 ,中序分左右
- 用 Map 快速定位根节点,避免每次遍历数组
- 按区间切割数组,递归建左右子树
- 标准分治递归思想,代码规范,面试必背模板
🎉 两道题终极口诀(秒记)
二叉树展开为链表
前序遍历存节点,循环拼接右指针,左边全部置为空
前序 + 中序还原二叉树
前序找根,中序分左右;递归切割,分治建树
🌟 总结
这两道题是二叉树最经典、最高频 的面试题!一道考察前序遍历 + 链表拼接 ,一道考察递归分治 + 还原二叉树,都是刷题必掌握核心知识点。
代码简洁、思路清晰,学会这两道,二叉树递归 / 遍历题型直接通关!