二叉树十题通关:从层序遍历到序列化(Python + C++)

二叉树十题通关:从层序遍历到序列化(Python + C++)

二叉树是面试中的重中之重,涉及递归、迭代、BFS、DFS、分治等多种思想。本文整理了10道经典题目,每道题包含:题目描述、解题思路、图解(文本示意)、Python代码、C++代码、复杂度分析。掌握这些,二叉树类题目基本通关。


📌 题目清单

题号 题目 核心考点
102 二叉树的层序遍历 BFS(队列)
104 二叉树的最大深度 DFS / BFS
226 翻转二叉树 递归 / 迭代
94 二叉树的中序遍历 迭代(栈)必会
105 从前序与中序遍历序列构造二叉树 递归分治
98 验证二叉搜索树 中序遍历有序 / 递归传递范围
236 二叉树的最近公共祖先 递归(后序遍历)
114 二叉树展开为链表 递归 / 迭代(右子树链接)
199 二叉树的右视图 BFS层序(每层最后一个)
297 二叉树的序列化与反序列化 BFS / DFS 设计(高频)

注:以下题目中使用的二叉树节点定义统一为:

python 复制代码
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

C++ 节点定义:

cpp 复制代码
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

1. 二叉树的层序遍历(LeetCode 102)

题目描述

给你二叉树的根节点 root,返回其节点值的层序遍历(即逐层地,从左到右访问所有节点)。

示例

输入:root = [3,9,20,null,null,15,7]

输出:[[3],[9,20],[15,7]]

解题思路

  • 使用队列进行广度优先搜索(BFS)。
  • 每次处理一层的所有节点,将它们的值加入当前层列表,并将其子节点加入队列。
  • 循环直到队列空。

图解

复制代码
        3
       / \
      9  20
         / \
        15  7

队列初始: [3]
处理第0层: 取出3 → 加入子节点9,20 → 当前层[3]
处理第1层: 取出9,20 → 9无子节点,20加入15,7 → 当前层[9,20]
处理第2层: 取出15,7 → 当前层[15,7]
结果 [[3],[9,20],[15,7]]

Python代码

python 复制代码
from collections import deque

def levelOrder(root):
    if not root:
        return []
    res = []
    q = deque([root])
    while q:
        level = []
        for _ in range(len(q)):
            node = q.popleft()
            level.append(node.val)
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)
        res.append(level)
    return res

C++代码

cpp 复制代码
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if (!root) return {};
        vector<vector<int>> res;
        queue<TreeNode*> q;
        q.push(root);
        while (!q.empty()) {
            int size = q.size();
            vector<int> level;
            for (int i = 0; i < size; ++i) {
                TreeNode* node = q.front(); q.pop();
                level.push_back(node->val);
                if (node->left) q.push(node->left);
                if (node->right) q.push(node->right);
            }
            res.push_back(level);
        }
        return res;
    }
};

复杂度分析

  • 时间复杂度:O(n),每个节点访问一次。
  • 空间复杂度:O(n),队列最坏存储满二叉树最后一层节点数约 n/2。

2. 二叉树的最大深度(LeetCode 104)

题目描述

给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

示例

输入:root = [3,9,20,null,null,15,7] → 输出:3

解题思路

  • 递归(DFS):最大深度 = 1 + max(左子树深度, 右子树深度)。
  • 迭代(BFS):层序遍历的层数即为最大深度。

图解(递归)

复制代码
        3
       / \
      9  20
         / \
        15  7
depth(3)=1+max(depth(9),depth(20))
depth(9)=1+max(0,0)=1
depth(20)=1+max(depth(15),depth(7))=1+1=2
depth(3)=1+max(1,2)=3

Python代码(递归)

python 复制代码
def maxDepth(root):
    if not root:
        return 0
    return 1 + max(maxDepth(root.left), maxDepth(root.right))

C++代码(递归)

cpp 复制代码
class Solution {
public:
    int maxDepth(TreeNode* root) {
        if (!root) return 0;
        return 1 + max(maxDepth(root->left), maxDepth(root->right));
    }
};

Python代码(BFS)

python 复制代码
def maxDepth(root):
    if not root:
        return 0
    q = deque([root])
    depth = 0
    while q:
        depth += 1
        for _ in range(len(q)):
            node = q.popleft()
            if node.left: q.append(node.left)
            if node.right: q.append(node.right)
    return depth

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:递归 O(height)(最差 O(n)),BFS O(n)。

3. 翻转二叉树(LeetCode 226)

题目描述

翻转一棵二叉树(左右子树交换)。

示例

输入:[4,2,7,1,3,6,9] → 输出:[4,7,2,9,6,3,1]

解题思路

  • 递归:交换当前节点的左右子树,然后递归翻转左右子树。
  • 迭代:使用队列或栈,每次交换节点的左右孩子。

图解

复制代码
      4               4
     / \             / \
    2   7    →      7   2
   / \ / \         / \ / \
  1  3 6 9        9  6 3  1

Python代码(递归)

python 复制代码
def invertTree(root):
    if not root:
        return None
    root.left, root.right = root.right, root.left
    invertTree(root.left)
    invertTree(root.right)
    return root

C++代码(递归)

cpp 复制代码
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (!root) return nullptr;
        swap(root->left, root->right);
        invertTree(root->left);
        invertTree(root->right);
        return root;
    }
};

Python代码(迭代)

python 复制代码
def invertTree(root):
    if not root:
        return None
    q = deque([root])
    while q:
        node = q.popleft()
        node.left, node.right = node.right, node.left
        if node.left: q.append(node.left)
        if node.right: q.append(node.right)
    return root

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:递归 O(height),迭代 O(n)。

4. 二叉树的中序遍历(LeetCode 94)

题目描述

给定一个二叉树的根节点,返回它的中序遍历(左-根-右)。

示例

输入:[1,null,2,3] → 输出:[1,3,2]

解题思路

  • 递归:左子树 → 根 → 右子树。
  • 迭代(必会):使用栈模拟递归过程。一直向左压栈,然后弹出访问,再转向右子树。

图解(迭代)

复制代码
    1
     \
      2
     /
    3

栈: []
cur=1 → 压1, cur=左(空)
弹出1访问 → cur=2
压2, cur=左(3)
压3, cur=左(空)
弹出3访问 → cur=右(空)
弹出2访问
结果 [1,3,2]

Python代码(递归)

python 复制代码
def inorderTraversal(root):
    res = []
    def dfs(node):
        if not node:
            return
        dfs(node.left)
        res.append(node.val)
        dfs(node.right)
    dfs(root)
    return res

C++代码(递归)

cpp 复制代码
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        inorder(root, res);
        return res;
    }
    void inorder(TreeNode* node, vector<int>& res) {
        if (!node) return;
        inorder(node->left, res);
        res.push_back(node->val);
        inorder(node->right, res);
    }
};

Python代码(迭代,必会)

python 复制代码
def inorderTraversal(root):
    res = []
    stack = []
    cur = root
    while cur or stack:
        while cur:
            stack.append(cur)
            cur = cur.left
        cur = stack.pop()
        res.append(cur.val)
        cur = cur.right
    return res

C++代码(迭代)

cpp 复制代码
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> st;
        TreeNode* cur = root;
        while (cur || !st.empty()) {
            while (cur) {
                st.push(cur);
                cur = cur->left;
            }
            cur = st.top(); st.pop();
            res.push_back(cur->val);
            cur = cur->right;
        }
        return res;
    }
};

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:递归 O(height),迭代 O(height)。

5. 从前序与中序遍历序列构造二叉树(LeetCode 105)

题目描述

给定一棵二叉树的前序遍历 preorder 和中序遍历 inorder,构造该二叉树。假设树中没有重复元素。

示例

输入:preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]

输出:[3,9,20,null,null,15,7]

解题思路

  • 前序遍历的第一个元素是根节点。
  • 在中序遍历中找到根节点的位置,左边为左子树的中序,右边为右子树的中序。
  • 根据左右子树的大小,在前序遍历中切分出左子树的前序和右子树的前序。
  • 递归构建。

图解

复制代码
pre: [3,9,20,15,7]
in:  [9,3,15,20,7]
根 = 3
左子树中序 [9] → 左子树大小1 → 左子树前序 [9]
右子树中序 [15,20,7] → 右子树前序 [20,15,7]
递归构建左右子树

Python代码

python 复制代码
def buildTree(preorder, inorder):
    if not preorder:
        return None
    root_val = preorder[0]
    root = TreeNode(root_val)
    idx = inorder.index(root_val)
    left_inorder = inorder[:idx]
    right_inorder = inorder[idx+1:]
    left_preorder = preorder[1:1+len(left_inorder)]
    right_preorder = preorder[1+len(left_inorder):]
    root.left = buildTree(left_preorder, left_inorder)
    root.right = buildTree(right_preorder, right_inorder)
    return root

C++代码(使用哈希表优化查找)

cpp 复制代码
class Solution {
public:
    unordered_map<int, int> idxMap;
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        for (int i = 0; i < inorder.size(); ++i) idxMap[inorder[i]] = i;
        return build(preorder, 0, preorder.size()-1, inorder, 0, inorder.size()-1);
    }
    TreeNode* build(vector<int>& pre, int pl, int pr, vector<int>& in, int il, int ir) {
        if (pl > pr) return nullptr;
        int rootVal = pre[pl];
        TreeNode* root = new TreeNode(rootVal);
        int idx = idxMap[rootVal];
        int leftSize = idx - il;
        root->left = build(pre, pl+1, pl+leftSize, in, il, idx-1);
        root->right = build(pre, pl+leftSize+1, pr, in, idx+1, ir);
        return root;
    }
};

复杂度分析

  • 时间复杂度:O(n),哈希表优化后每个节点处理一次。
  • 空间复杂度:O(n),递归栈和哈希表。

6. 验证二叉搜索树(LeetCode 98)

题目描述

给定一个二叉树,判断其是否是一个有效的二叉搜索树(BST)。BST 定义:左子树所有节点值 < 根节点值 < 右子树所有节点值。

示例

输入:[2,1,3] → 输出:true

输入:[5,1,4,null,null,3,6] → 输出:false

解题思路

  • 方法一(中序遍历):BST 的中序遍历结果是严格递增的。遍历过程中检查前驱节点值是否小于当前节点。
  • 方法二(递归传递范围):每个节点有一个合法的取值范围 (min, max),递归检查。

图解(中序遍历)

复制代码
    2
   / \
  1   3
中序: [1,2,3] 递增 → true

Python代码(中序遍历)

python 复制代码
def isValidBST(root):
    stack = []
    cur = root
    prev = None
    while cur or stack:
        while cur:
            stack.append(cur)
            cur = cur.left
        cur = stack.pop()
        if prev is not None and prev.val >= cur.val:
            return False
        prev = cur
        cur = cur.right
    return True

C++代码(递归范围)

cpp 复制代码
class Solution {
public:
    bool isValidBST(TreeNode* root) {
        return dfs(root, LONG_MIN, LONG_MAX);
    }
    bool dfs(TreeNode* node, long lower, long upper) {
        if (!node) return true;
        if (node->val <= lower || node->val >= upper) return false;
        return dfs(node->left, lower, node->val) && dfs(node->right, node->val, upper);
    }
};

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:O(height)。

7. 二叉树的最近公共祖先(LeetCode 236)

题目描述

给定一棵二叉树和两个节点 p、q,找出它们的最近公共祖先(LCA)。

示例

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p=5, q=1 → 输出:3

解题思路

  • 递归后序遍历:
    • 如果当前节点为 null,返回 null。
    • 如果当前节点等于 p 或 q,返回当前节点。
    • 递归在左右子树中寻找 p 和 q。
    • 如果左右子树返回值都不为空,说明当前节点就是 LCA。
    • 如果一边为空,返回另一边。

图解

复制代码
        3
       / \
      5   1
     / \ / \
    6  2 0 8
      / \
     7   4
p=5, q=4
递归到5的左子树6 -> null, 右子树2 -> 2的左7 null 右4返回4 -> 2的左右返回(null,4)-> 返回4
5的左右返回(null,4)-> 返回4? 不对,应返回5(因为5等于p)。需修正逻辑:若节点等于p或q直接返回自身。
正确过程:5等于p,直接返回5,不再深入。同时右子树递归返回4,但5已经返回了,所以祖先为5。

Python代码

python 复制代码
def lowestCommonAncestor(root, p, q):
    if not root or root == p or root == q:
        return root
    left = lowestCommonAncestor(root.left, p, q)
    right = lowestCommonAncestor(root.right, p, q)
    if left and right:
        return root
    return left or right

C++代码

cpp 复制代码
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (!root || root == p || root == q) return root;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        if (left && right) return root;
        return left ? left : right;
    }
};

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:O(height)。

8. 二叉树展开为链表(LeetCode 114)

题目描述

给定一个二叉树,将其原地展开为单链表(使用右孩子指针指向下一个节点,左孩子始终为 null)。

示例

输入:[1,2,5,3,4,null,6] → 输出:[1,null,2,null,3,null,4,null,5,null,6]

解题思路

  • 递归:先展平左子树,再展平右子树,然后将左子树接到根与右子树之间。
  • 迭代:从根开始,如果左子树存在,找到左子树的最右节点,将原右子树接到该最右节点的右边,然后将左子树整体移到右边。

图解(迭代)

复制代码
    1
   / \
  2   5
 / \   \
3   4   6

步骤1: 1的左子树2存在,找左子树最右节点4,将5接到4.right,然后将2作为1.right,左孩子置空
    1
     \
      2
     / \
    3   4
         \
          5
           \
            6
然后处理节点2,重复...
最终得到右链表

Python代码(递归)

python 复制代码
def flatten(root):
    if not root:
        return
    flatten(root.left)
    flatten(root.right)
    left = root.left
    right = root.right
    root.left = None
    root.right = left
    # 找到当前右子树的末尾
    p = root
    while p.right:
        p = p.right
    p.right = right

C++代码(迭代)

cpp 复制代码
class Solution {
public:
    void flatten(TreeNode* root) {
        TreeNode* cur = root;
        while (cur) {
            if (cur->left) {
                TreeNode* leftRight = cur->left;
                while (leftRight->right) leftRight = leftRight->right;
                leftRight->right = cur->right;
                cur->right = cur->left;
                cur->left = nullptr;
            }
            cur = cur->right;
        }
    }
};

复杂度分析

  • 时间复杂度:O(n),每个节点访问常数次。
  • 空间复杂度:递归 O(height),迭代 O(1)。

9. 二叉树的右视图(LeetCode 199)

题目描述

给定一棵二叉树,想象自己站在它的右侧,返回从顶部到底部看到的节点值。

示例

输入:[1,2,3,null,5,null,4] → 输出:[1,3,4]

解题思路

  • 使用层序遍历(BFS),每层取最后一个节点的值。
  • 也可以使用 DFS 先右后左,记录深度,第一次访问该深度的节点即为右视图。

图解(BFS)

复制代码
    1
   / \
  2   3
   \   \
    5   4
层序: 第0层[1] → 取1
第1层[2,3] → 取3
第2层[5,4] → 取4
结果 [1,3,4]

Python代码(BFS)

python 复制代码
def rightSideView(root):
    if not root:
        return []
    res = []
    q = deque([root])
    while q:
        level_size = len(q)
        for i in range(level_size):
            node = q.popleft()
            if i == level_size - 1:
                res.append(node.val)
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)
    return res

C++代码(DFS,先右后左)

cpp 复制代码
class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        vector<int> res;
        dfs(root, 0, res);
        return res;
    }
    void dfs(TreeNode* node, int depth, vector<int>& res) {
        if (!node) return;
        if (depth == res.size()) res.push_back(node->val);
        dfs(node->right, depth+1, res);
        dfs(node->left, depth+1, res);
    }
};

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:BFS O(n),DFS O(height)。

10. 二叉树的序列化与反序列化(LeetCode 297)

题目描述

设计一个算法,将二叉树序列化为字符串,并能从字符串反序列化回原树。不限制格式,只需能还原。

示例

输入:[1,2,3,null,null,4,5] → 序列化 → 反序列化还原。

解题思路

  • BFS(层序) :使用队列进行层序遍历,将空节点标记为 "null",用分隔符连接。反序列化时同样用队列按层构建。
  • DFS(前序):递归前序遍历,遇到 null 也记录,反序列化时同样递归构建。

图解(BFS)

复制代码
    1
   / \
  2   3
     / \
    4   5
序列化: "1,2,3,null,null,4,5,null,null,null,null"
反序列化: 用队列存储节点,依次赋值左右孩子

Python代码(BFS 序列化)

python 复制代码
from collections import deque

class Codec:
    def serialize(self, root):
        if not root:
            return ""
        q = deque([root])
        res = []
        while q:
            node = q.popleft()
            if node:
                res.append(str(node.val))
                q.append(node.left)
                q.append(node.right)
            else:
                res.append("null")
        return ",".join(res)

    def deserialize(self, data):
        if not data:
            return None
        vals = data.split(",")
        root = TreeNode(int(vals[0]))
        q = deque([root])
        i = 1
        while q:
            node = q.popleft()
            if vals[i] != "null":
                node.left = TreeNode(int(vals[i]))
                q.append(node.left)
            i += 1
            if vals[i] != "null":
                node.right = TreeNode(int(vals[i]))
                q.append(node.right)
            i += 1
        return root

C++代码(DFS 前序)

cpp 复制代码
class Codec {
public:
    string serialize(TreeNode* root) {
        ostringstream out;
        serialize(root, out);
        return out.str();
    }
    void serialize(TreeNode* root, ostringstream& out) {
        if (!root) out << "null ";
        else {
            out << root->val << " ";
            serialize(root->left, out);
            serialize(root->right, out);
        }
    }
    TreeNode* deserialize(string data) {
        istringstream in(data);
        return deserialize(in);
    }
    TreeNode* deserialize(istringstream& in) {
        string val;
        in >> val;
        if (val == "null") return nullptr;
        TreeNode* node = new TreeNode(stoi(val));
        node->left = deserialize(in);
        node->right = deserialize(in);
        return node;
    }
};

复杂度分析

  • 时间复杂度:O(n),每个节点访问一次。
  • 空间复杂度:O(n),存储序列化字符串和队列/栈。

🎯 总结

题目 核心技巧 时间复杂度 空间复杂度
102. 层序遍历 BFS(队列) O(n) O(n)
104. 最大深度 DFS / BFS O(n) O(height) / O(n)
226. 翻转二叉树 递归交换子树 O(n) O(height)
94. 中序遍历 迭代栈(必会) O(n) O(height)
105. 构建二叉树 前中序分治 + 哈希表 O(n) O(n)
98. 验证BST 中序递增 / 范围递归 O(n) O(height)
236. 最近公共祖先 后序递归 O(n) O(height)
114. 展开链表 迭代(右子树链接) O(n) O(1)
199. 右视图 BFS每层最后一个 O(n) O(n)
297. 序列化 BFS/DFS + 标记空节点 O(n) O(n)

二叉树的题目主要考察递归思维、遍历框架(前中后序、层序)以及如何利用遍历顺序解决问题。建议熟练掌握递归和迭代两种写法,尤其是中序遍历的迭代实现(面试高频)。

相关推荐
后季暖1 小时前
python装饰器解释
开发语言·python
南境十里·墨染春水1 小时前
线程池学习(一) 理解 进程 线程 协程及上下文切换
java·开发语言·学习
王老师青少年编程1 小时前
csp信奥赛C++高频考点专项训练之字符串 --【回文字符串】:最大回文数
c++·字符串·csp·高频考点·信奥赛·回文字符串·最大回文数
知兀1 小时前
@Accessors(chain = true)和@Builder链式风格差异
java·开发语言
m0_733565461 小时前
c++如何在内存极小的单片机上读写SD卡文件_FatFs库裁剪与移植【实战】
jvm·数据库·python
Mr.H01271 小时前
C语言MQTT学习系列(3篇):第一篇:从零开始学MQTT(C语言版):入门必看,跑通最简Demo
c语言·网络·学习
邪修king2 小时前
UE5 进阶篇第一弹:中期架构升级 —— 组件化开发与 Gameplay 框架实战
c++·游戏·架构·ue5
weixin_459753943 小时前
golang如何实现Trace上下文传播_golang Trace上下文传播实现思路
jvm·数据库·python
zhangfeng11333 小时前
openclaw skills 小龙虾技能 通讯仿真 matlab skill Simulink Agentic Toolkit,通过kimi找到,mcp通讯
开发语言·matlab·openclaw·通讯仿真