【剑指offer 2】 JZ7 重建二叉树

题目

牛客 JZ7 重建二叉树

栈辅助方法

通过栈辅助的迭代方式,利用前序和中序遍历的特性重构二叉树。其核心思路是模拟递归过程中的节点处理顺序,结合栈的先进后出特性管理父节点。以下是分步骤解析:


一、算法核心思路

  1. 前序遍历确定根节点
    前序遍历的首元素为根节点(即pre[0]),首先创建根节点并压入栈中。

  2. 中序遍历定位左右子树分界
    通过中序遍历数组(vin)的指针j,判断当前处理的节点是否属于左子树。若当前节点值与vin[j]相等,说明左子树已处理完毕,需转向处理右子树。

  3. 栈辅助回溯父节点
    栈用于暂存未处理完右子树的父节点。当需要切换至右子树时,通过弹栈回溯到最近的未处理右子树的父节点。


二、代码分步解析

class Solution {
public:
    TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin) {
        // 初始化
        if (pre.empty() || vin.empty()) return nullptr;
        TreeNode* root = new TreeNode(pre[0]); // 前序首元素为根
        stack<TreeNode*> s;
        TreeNode* cur = root;
        int j = 0; // 中序指针

        // 遍历前序数组剩余元素
        for (int i = 1; i < pre.size(); i++) {
            if (cur->val != vin[j]) { 
                // 情况1:当前元素是左子节点
                cur->left = new TreeNode(pre[i]);
                s.push(cur);    // 父节点压栈
                cur = cur->left; // 继续处理左子树
            } else { 
                // 情况2:左子树处理完毕,转向右子树
                j++;
                while (!s.empty() && s.top()->val == vin[j]) {
                    cur = s.top(); // 回溯到最近的未处理右子树的祖先
                    s.pop();
                    j++;
                }
                // 添加右子节点
                cur->right = new TreeNode(pre[i]);
                cur = cur->right; // 处理右子树
            }
        }
        return root;
    }
};

关键步骤详解

  1. 初始化阶段
    • 前序首元素创建根节点(root),中序指针j初始化为0。

    • 栈用于存储待处理右子树的父节点。

  2. 处理左子节点
    • 条件:当前节点值不等于vin[j](说明当前前序元素属于左子树)。

    • 操作:将前序元素作为左子节点,父节点压栈,继续向左子树深入。

  3. 处理右子节点
    • 触发条件:当前节点值等于vin[j](左子树处理完毕)。

    • 回溯父节点:通过弹栈找到第一个与vin[j]不匹配的祖先节点(即该祖先的右子树尚未处理)。

    • 添加右子节点:将前序元素作为右子节点,并转向处理右子树。


三、算法复杂度与优化
• 时间复杂度:O(n),每个节点仅被访问一次。

• 空间复杂度:O(n),栈空间在最坏情况下存储所有节点。

对比递归法的优势
• 避免递归栈溢出:适合处理大规模数据。

• 逻辑紧凑:通过单层循环实现,减少函数调用开销。

局限性
• 依赖无重复值:若节点值重复,需额外处理(如哈希表记录索引)。

• 可读性较低:需结合前序和中序的指针变化理解逻辑。


四、示例验证
以输入 pre=[3,9,20,15,7]vin=[9,3,15,20,7] 为例:

  1. 根节点为3,压栈。j=0vin[0]=9)。
  2. pre[1]=9作为3的左子节点,压栈3,cur指向9。
  3. pre[2]=20时,cur->val=9vin[j]=9匹配,回溯到3,添加20为右子节点。
  4. 后续按相同逻辑处理右子树,最终构建完整二叉树。

五、总结
该算法通过栈模拟递归过程,巧妙利用前序和中序的特性,逐步构建二叉树。其核心在于通过中序指针j和栈的回溯机制,精准定位左右子树的分界点。如需进一步优化,可结合哈希表缓存中序索引,减少查找时间。

posted @ 2025-05-08 10:06  围城chen  阅读(28)  评论(0)    收藏  举报