二叉树综合拔高:遍历还原与OJ题拓展训练

🏠个人主页:黎雁

🎬作者简介:C/C++/JAVA后端开发学习者

❄️个人专栏:C语言数据结构(C语言)EasyX游戏规划程序人生

✨ 从来绝巘须孤往,万里同尘即玉京

文章目录

  • 二叉树综合拔高:遍历还原与OJ题拓展训练✨
    • 文章摘要
    • 一、知识回顾:二叉树的遍历与还原核心逻辑
    • [二、核心考点:由遍历序列还原二叉树 🔍](#二、核心考点:由遍历序列还原二叉树 🔍)
      • [1. 前序+中序还原二叉树](#1. 前序+中序还原二叉树)
      • [2. 后序+中序还原二叉树](#2. 后序+中序还原二叉树)
    • [三、拓展OJ题:二叉树高频进阶题深度解析 🔥](#三、拓展OJ题:二叉树高频进阶题深度解析 🔥)
      • [1. OJ题1:二叉树的最近公共祖先(LeetCode 236)](#1. OJ题1:二叉树的最近公共祖先(LeetCode 236))
      • [2. OJ题2:路径总和(LeetCode 112)](#2. OJ题2:路径总和(LeetCode 112))
      • [3. OJ题3:对称二叉树(LeetCode 101)](#3. OJ题3:对称二叉树(LeetCode 101))
    • [四、进阶技巧:二叉树的非递归遍历与Morris遍历 🚀](#四、进阶技巧:二叉树的非递归遍历与Morris遍历 🚀)
      • [1. 二叉树的非递归前序遍历](#1. 二叉树的非递归前序遍历)
      • [2. Morris遍历(空间复杂度O(1)的遍历)](#2. Morris遍历(空间复杂度O(1)的遍历))
    • 五、写在最后

二叉树综合拔高:遍历还原与OJ题拓展训练✨

你好!欢迎来到数据结构系列二叉树篇的第三篇综合拔高内容~

在前两篇中,我们夯实了二叉树的基础概念,掌握了节点计数、层序遍历、经典OJ题解等核心实战技能。今天,我们将聚焦二叉树的综合拔高知识点 ,从遍历序列还原二叉树的核心逻辑,到更多高频OJ题的深度解析,再到二叉树的进阶应用技巧,全方位提升你对二叉树的理解和解题能力。这些内容是笔试和面试中的难点与重点,也是区分普通开发者和优秀开发者的关键🌳

准备好了吗?让我们一起攻克二叉树的最后一道关卡,实现从入门到精通的跨越!🚀


文章摘要

本文为数据结构系列二叉树篇第三篇综合拔高内容,聚焦二叉树的进阶核心考点。深入讲解由遍历序列还原二叉树的核心逻辑,包括前序+中序、后序+中序的还原方法。结合二叉树的最近公共祖先、路径总和、对称二叉树等高频OJ题,拆解解题思路并提供高效代码实现。补充二叉树的非递归遍历、 Morris 遍历等进阶技巧,全方位提升二叉树的综合解题能力。

阅读时长 :约35分钟
阅读建议

  1. 初学者:先掌握由遍历序列还原二叉树的核心逻辑,再练习基础OJ题
  2. 刷题备考者:重点记忆最近公共祖先、路径总和的解题模板,理解递归与迭代的结合
  3. 面试冲刺者:熟练掌握非递归遍历的实现,了解 Morris 遍历的核心思想
  4. 查漏补缺者:聚焦对称二叉树的判断逻辑,理解递归与迭代的两种实现方式

一、知识回顾:二叉树的遍历与还原核心逻辑

在进入综合拔高内容前,我们先回顾二叉树遍历的核心知识点,这是还原二叉树的基础:

  1. 前序遍历:根 → 左 → 右,第一个节点是根节点。
  2. 中序遍历:左 → 根 → 右,根节点将序列分为左子树和右子树。
  3. 后序遍历:左 → 右 → 根,最后一个节点是根节点。
  4. 层序遍历:一层一层遍历,利用队列实现。

核心原则仅通过前序、后序或层序遍历序列,无法唯一还原二叉树;必须结合中序遍历序列,才能唯一还原二叉树


二、核心考点:由遍历序列还原二叉树 🔍

由遍历序列还原二叉树是二叉树的核心考点,也是面试中的高频题。我们重点讲解两种最常见的还原方式:前序+中序、后序+中序。

1. 前序+中序还原二叉树

核心逻辑

  1. 前序序列的第一个元素是根节点。
  2. 在中序序列中找到根节点,根节点左侧是左子树的中序序列,右侧是右子树的中序序列。
  3. 根据左子树和右子树的节点个数,在前序序列中划分出左子树和右子树的前序序列。
  4. 递归还原左子树和右子树,构建完整的二叉树。

示例

  • 前序序列:ABDHECFG
  • 中序序列:DHBEACFG
  • 根节点:A,左子树中序序列:DHBE,右子树中序序列:CFG
  • 左子树前序序列:BDHE,右子树前序序列:CFG
  • 递归还原左子树和右子树。

2. 后序+中序还原二叉树

核心逻辑

  1. 后序序列的最后一个元素是根节点。
  2. 在中序序列中找到根节点,根节点左侧是左子树的中序序列,右侧是右子树的中序序列。
  3. 根据左子树和右子树的节点个数,在后序序列中划分出左子树和右子树的后序序列。
  4. 递归还原左子树和右子树,构建完整的二叉树。

示例

  • 后序序列:DHEBFGCA
  • 中序序列:DHBEACFG
  • 根节点:A,左子树中序序列:DHBE,右子树中序序列:CFG
  • 左子树后序序列:DHEB,右子树后序序列:FGC
  • 递归还原左子树和右子树。

💡 核心技巧 :由遍历序列还原二叉树的关键是找到根节点,划分左右子树的序列,递归构建。中序序列的作用是划分左右子树,这是唯一还原二叉树的关键。


三、拓展OJ题:二叉树高频进阶题深度解析 🔥

接下来,我们结合三道二叉树的高频进阶OJ题,讲解解题思路和代码实现。这些题目覆盖了最近公共祖先、路径总和、对称二叉树等核心考点,是笔试和面试的重点。

1. OJ题1:二叉树的最近公共祖先(LeetCode 236)

题目要求:给定一个二叉树,找到该树中两个指定节点的最近公共祖先。最近公共祖先是指在树中同时拥有 p 和 q 作为后代的最深节点(一个节点也可以是它自己的后代)。

解题思路(递归分治)

  1. 若根节点为空,返回 NULL。
  2. 若根节点是 p 或 q,返回根节点。
  3. 递归在左子树中查找 p 和 q 的最近公共祖先,得到 left。
  4. 递归在右子树中查找 p 和 q 的最近公共祖先,得到 right。
  5. 若 left 和 right 都不为空,说明 p 和 q 分别在左右子树中,根节点是最近公共祖先。
  6. 若 left 为空,说明 p 和 q 都在右子树中,返回 right。
  7. 若 right 为空,说明 p 和 q 都在左子树中,返回 left。

代码实现

c 复制代码
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
    if (root == NULL || root == p || root == q) {
        return root;
    }
    struct TreeNode* left = lowestCommonAncestor(root->left, p, q);
    struct TreeNode* right = lowestCommonAncestor(root->right, p, q);
    if (left == NULL) {
        return right;
    }
    if (right == NULL) {
        return left;
    }
    return root;
}

2. OJ题2:路径总和(LeetCode 112)

题目要求:给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值的和等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。

解题思路(递归分治)

  1. 若根节点为空,返回 false。
  2. 若根节点是叶子节点,判断根节点的值是否等于 targetSum。
  3. 递归判断左子树是否存在路径和为 targetSum - root->val 的路径。
  4. 递归判断右子树是否存在路径和为 targetSum - root->val 的路径。
  5. 若左子树或右子树存在这样的路径,返回 true,否则返回 false。

代码实现

c 复制代码
bool hasPathSum(struct TreeNode* root, int targetSum) {
    if (root == NULL) {
        return false;
    }
    if (root->left == NULL && root->right == NULL) {
        return root->val == targetSum;
    }
    return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
}

3. OJ题3:对称二叉树(LeetCode 101)

题目要求:给你一个二叉树的根节点 root ,检查它是否轴对称。

解题思路(递归分治)

  1. 若根节点为空,返回 true。
  2. 定义辅助函数,判断两个子树是否对称。
  3. 两个子树对称的条件:
    • 两个子树的根节点值相等。
    • 第一个子树的左子树与第二个子树的右子树对称。
    • 第一个子树的右子树与第二个子树的左子树对称。
  4. 递归判断根节点的左右子树是否对称。

代码实现

c 复制代码
bool isSymmetricHelper(struct TreeNode* left, struct TreeNode* right) {
    if (left == NULL && right == NULL) {
        return true;
    }
    if (left == NULL || right == NULL) {
        return false;
    }
    return (left->val == right->val) && isSymmetricHelper(left->left, right->right) && isSymmetricHelper(left->right, right->left);
}

bool isSymmetric(struct TreeNode* root) {
    if (root == NULL) {
        return true;
    }
    return isSymmetricHelper(root->left, root->right);
}

四、进阶技巧:二叉树的非递归遍历与Morris遍历 🚀

1. 二叉树的非递归前序遍历

核心思想:利用栈辅助实现,先将根节点入栈,然后循环弹出栈顶节点,访问该节点,再将右孩子入栈,最后将左孩子入栈(因为栈是先进后出,左孩子后入栈先弹出)。

代码实现

c 复制代码
void preOrderNonRecursive(struct TreeNode* root) {
    if (root == NULL) {
        return;
    }
    struct TreeNode* stack[100];
    int top = -1;
    stack[++top] = root;
    while (top != -1) {
        struct TreeNode* node = stack[top--];
        printf("%d ", node->val);
        if (node->right != NULL) {
            stack[++top] = node->right;
        }
        if (node->left != NULL) {
            stack[++top] = node->left;
        }
    }
}

2. Morris遍历(空间复杂度O(1)的遍历)

核心思想:利用二叉树的空闲指针(空的右孩子指针),实现常数空间复杂度的遍历。通过构建临时的前驱节点,将二叉树转换为链表结构,然后遍历链表,最后恢复二叉树的原始结构。

适用场景:当空间复杂度要求较高时,Morris遍历是最优选择。它可以实现前序、中序、后序遍历,空间复杂度均为O(1),时间复杂度为O(n)。


五、写在最后

恭喜你!二叉树篇的所有内容至此圆满结束🎉~

从二叉树的基础概念、三种深度优先遍历,到节点计数、层序遍历、经典OJ题解,再到遍历序列还原二叉树、进阶OJ题、非递归遍历与Morris遍历,你已经完成了二叉树的全体系学习,实现了从入门到精通的跨越:

  • 掌握了二叉树的核心概念和遍历方式,能独立实现递归和非递归遍历。
  • 能解决二叉树的经典OJ题,具备较强的算法解题能力。
  • 理解了由遍历序列还原二叉树的核心逻辑,掌握了面试高频考点。
  • 了解了二叉树的进阶技巧,如非递归遍历、Morris遍历,提升了综合竞争力。

二叉树是数据结构的核心基础 ,也是算法面试的必考内容。建议你多敲几遍代码,多做几道OJ题,真正理解递归分治的核心思想------这不仅是解决二叉树问题的关键,更是解决所有复杂算法问题的基础。

下一个系列,我们将进入图论的世界,学习更复杂的非线性结构,提升数据结构的应用能力~😜


点赞+收藏+关注,跟着系列内容一步步吃透数据结构!你的支持是我创作的最大动力~👍

相关推荐
漫随流水18 小时前
leetcode算法(111.二叉树的最小深度)
数据结构·算法·leetcode·二叉树
你怎么知道我是队长1 天前
C语言---枚举变量
c语言·开发语言
POLITE31 天前
Leetcode 23. 合并 K 个升序链表 (Day 12)
算法·leetcode·链表
会员果汁1 天前
leetcode-动态规划-买卖股票
算法·leetcode·动态规划
橘颂TA1 天前
【剑斩OFFER】算法的暴力美学——二进制求和
算法·leetcode·哈希算法·散列表·结构与算法
尋有緣1 天前
力扣1355-活动参与者
大数据·数据库·leetcode·oracle·数据库开发
kaikaile19951 天前
基于拥挤距离的多目标粒子群优化算法(MO-PSO-CD)详解
数据结构·算法
不忘不弃1 天前
求两组数的平均值
数据结构·算法
leaves falling1 天前
迭代实现 斐波那契数列
数据结构·算法