【LeetCode-面试算法经典-Java实现】【105-Construct Binary Tree from Preorder and Inorder Traversal(构造二叉树)】

本文介绍了一种利用前序和中序遍历序列构建二叉树的算法,并提供了两种不同的Java实现方式。该算法适用于没有重复元素的二叉树构建场景。

【105-Construct Binary Tree from Preorder and Inorder Traversal(通过前序和中序遍历构造二叉树)】


【LeetCode-面试算法经典-Java实现】【所有题目目录索引】

原题

  Given preorder and inorder traversal of a tree, construct the binary tree.
  Note:
  You may assume that duplicates do not exist in the tree.

题目大意

  给定一个前序和中序遍历序列,构建一个二叉树
  注意:
   - 二叉树中元素重复元素

解题思路

  前序遍历第一个元素是根结点(k),在中序遍历序列中找值为k的下标idx,idx将中序遍历序列分成左右子树,对前序遍历序列也一样,可进行递归操作

代码实现

树结点类

public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

算法实现类一:

public class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder == null || preorder.length ==0){
            return null;
        }
        HashMap<Integer, Integer> inorderMap = new HashMap<Integer, Integer>();
        for (int i=0;i<inorder.length;i++){
            inorderMap.put(inorder[i],i);
        }

        Deque<TreeNode> stack = new LinkedList<TreeNode>();
        TreeNode root = new TreeNode(preorder[0]);
        stack.push(root);
        for (int i=1;i<preorder.length;i++){
            TreeNode top = stack.peek();
            int indexTop = inorderMap.get(top.val);
            int indexVal = inorderMap.get(preorder[i]);

            TreeNode node = new TreeNode(preorder[i]);

            if (indexVal<indexTop){
                top.left=node;
            }
            else{
            while (indexVal>indexTop){
                    top = stack.pop();
                    indexTop = stack.isEmpty()?Integer.MAX_VALUE:inorderMap.get(stack.peek().val);
                }
                top.right = node;
            }
            stack.push(node);
        }
        return root;
    }
}

算法实现类二:(会超时)

public class Solution {

    public TreeNode buildTree(int[] preorder, int[] inorder) {

        // 参数校验
        if (preorder == null || inorder == null || preorder.length == 0
                || preorder.length != inorder.length) {
            return null;
        }
        return solve(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
    }

    /**
     * 构建二叉树,数据输入的正确性由输入数据自己保证
     *
     * @param preorder 先序遍历的结果
     * @param x        先序遍历的开始位置
     * @param y        先序遍历的结束位置
     * @param inorder  中序遍历的结果
     * @param i        中序遍历的开始位置
     * @param j        中序遍历的结束位置
     * @return 二叉树的根结点
     */
    public TreeNode solve(int[] preorder, int x, int y, int[] inorder, int i, int j) {

        if (x >= 0 && x <= y && i >= 0 && i <= j) {
            // 只有一个元素
            if (x == y) {
                return new TreeNode(preorder[x]);
            } else if (x < y) {
                // 记录根结点的索引
                int idx = i;
                while (idx <= j && inorder[idx] != preorder[x]) {
                    idx++;
                }

                // 创建根结点
                TreeNode root = new TreeNode(inorder[idx]);

                // 左子树的结点个数
                int leftLength = idx - i;
                //
                if (leftLength > 0) {
                    // x + 1, x + leftLength:左子树起始和结束位置
                    root.left = solve(preorder, x + 1, x + leftLength, inorder, i, idx - 1);
                }

                // 右子树的结点个数
                int rightLength = j - idx;
                if (rightLength > 0) {
                    // x + leftLength + 1, y:右子树起始和结束位置
                    root.right = solve(preorder, x + leftLength + 1, y, inorder, idx + 1, j);
                }
                return root;
            }
        }

        return null;
    }
}

评测结果

  点击图片,鼠标不释放,拖动一段位置,释放后在新的窗口中查看完整图片。

这里写图片描述

特别说明

欢迎转载,转载请注明出处【http://blog.csdn.net/derrantcm/article/details/47371985

下面是该段代码的 **Visual Studio 可运行完整版本**,包含: - `TreeNode` 节点定义 - `buildTree` 函数的完整实现(从前序和中序遍历构造二叉树- 主函数中测试用例 - 打印构建后的二叉树前序遍历验证) --- ## ✅ Visual Studio 完整运行代码 ```cpp #include <iostream> #include <vector> #include <algorithm> #include <ranges> using namespace std; // 二叉树节点定义 struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {} }; class Solution { public: TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { if (preorder.empty()) { return nullptr; } // 查找根节点在中序遍历中的位置 auto root_it = ranges::find(inorder, preorder[0]); int left_size = distance(inorder.begin(), root_it); // 左子树节点数量 // 划分左子树和右子树的前序和中序序列 vector<int> pre_left(preorder.begin() + 1, preorder.begin() + 1 + left_size); vector<int> pre_right(preorder.begin() + 1 + left_size, preorder.end()); vector<int> in_left(inorder.begin(), inorder.begin() + left_size); vector<int> in_right(inorder.begin() + 1 + left_size, inorder.end()); // 递归构建左右子树 TreeNode* left = buildTree(pre_left, in_left); TreeNode* right = buildTree(pre_right, in_right); return new TreeNode(preorder[0], left, right); } // 前序遍历打印二叉树 void preorderPrint(TreeNode* root) { if (root == nullptr) { cout << "null "; return; } cout << root->val << " "; preorderPrint(root->left); preorderPrint(root->right); } // 析构函数(手动释放内存) void deleteTree(TreeNode* root) { if (root == nullptr) return; deleteTree(root->left); deleteTree(root->right); delete root; } }; int main() { Solution sol; // 示例输入 vector<int> preorder = {3, 9, 20, 15, 7}; vector<int> inorder = {9, 3, 15, 20, 7}; // 构建二叉树 TreeNode* root = sol.buildTree(preorder, inorder); // 打印前序遍历结果以验证是否正确 cout << "构建的二叉树前序遍历结果: "; sol.preorderPrint(root); cout << endl; // 释放内存 sol.deleteTree(root); return 0; } ``` --- ## 📌 编译与运行说明(适用于 Visual Studio) 1. 打开 Visual Studio 2. 创建一个 **C++ 控制台应用程序(Console Application)** 3. 删除默认生成的代码内容 4. 将上面的代码粘贴到 `.cpp` 文件中(如 `main.cpp`) 5. 确保你的编译器支持 **C++20**,因为使用了 `<ranges>` 和范围查找 - VS 2022 及以上版本支持 C++20 6. 按 `Ctrl + F5` 或点击 **“本地 Windows 调试器”** 运行程序 --- ## 🧾 输出结果示例 ``` 构建的二叉树前序遍历结果: 3 9 null null 20 15 null null 7 null null ``` 说明构建成功,结构如下: ``` 3 / \ 9 20 / \ 15 7 ``` --- ## 🧠 代码解释 - `preorder[0]` 是当前子树的根节点。 - 在 `inorder` 中找到该根节点,左边就是左子树,右边就是右子树。 - 根据左子树大小,划分 `preorder` 中的左右子树。 - 递归构造左右子树。 - 最后返回构造好的当前子树根节点。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值