【leetcode】105. 从前序与中序遍历序列构造二叉树(24年北理工计算机技术复试上机最后一道题目)

原题链接:105. 从前序与中序遍历序列构造二叉树

题目

题解:

先写代码:(讲解代码即讲解思路)

/**
 * Definition for a binary tree node.
 * 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) {}
 * };
 */
class Solution {
public:
    map<int,int> f;
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        for (int i = 0; i < preorder.size(); i++) f[inorder[i]] = i;

        TreeNode* root = dfs(0, inorder.size()-1, 0, preorder.size()-1, preorder);
        return root;
    }

    TreeNode* dfs(int is, int ie, int ps, int pe, vector<int> pre) {
        if (ie < is || pe < ps) return nullptr;
        TreeNode* cur = new TreeNode();
        cur->val = pre[ps];
        int ri = f[pre[ps]];
        cur->left = dfs(is, ri-1, ps+1, ps+ri-is, pre);
        cur->right = dfs(ri+1, ie, ps+ri-is+1, pe, pre);
        return cur;
    }
};

前序是根左右,中序是左根右。使用递归逐步构造左右子树。

图1

我们在前序序列中找到一个根之后,在中序序列中以根为分界点分为左子树和右子树,然后递归构建左子树和右子树。对于我们当前在前序序列中找到的点n,它便是当前子树的根节点。

递归函数dfs参数解释:下面说的子树是指左子树或者是右子树

  • is 表示子树在中序序列中的起始位置
  • ie 表示子树在中序序列中的结束位置
  • ps 表示子树在前序序列中的起始位置
  • pe 表示子树在前序序列中的结束位置
  • pre 表示前序序列

递归函数的关键便是这些位置下标的计算,例如在图1中,当我们在前序序列中找到一个根3时,接着我们在中序序列中找到他的位置,记为ri,我们首先可以确定以3为根的子树的左子树在中序序列中的范围为:[is, ri-1];右子树的范围为:[ri+1, ie]

如何在前序序列中确定左子树、右子树的范围呢?首先,前序序列中左子树的开始坐标为ps+1,这不难理解。左子树的结束坐标是根据左子树的大小确定的。因为我们在中序序列中已经知道左子树的范围为:[is, ri-1],那么左子树中节点的个数为:ri-is。那么前序序列中左子树的结束坐标就是:开始坐标+左子树节点个数-1,即:ps+ri-is。所以左子树在前序序列中范围为:[ps+1, ps+ri-is]

所以我们算出了以3为根节点的左子树的递归函数的所有参数:

dfs(is, ri-1, ps+1, ps+ri-is, pre)

同理,右子树在前序序列的开始坐标是:左子树的结束坐标+1,ps+ri-is+1;结束坐标是pe。所以右子树的递归函数为:

dfs(ri+1, ie, ps+ri-is+1, pe, pre)

至此,我们解决了最关键的问题。

还有一个,在前序序列中找到了根节点,如何快速求出他在中序序列中的下标,这里用到了map映射,原理很简单,直接看代码应该就能理解,不再详细解释。

力扣106.从中序与后序遍历序列构造二叉树

这道题和105是一样的,我们只要重新计算一下区间即可:

root->left = dfs_inAndPost(is, ri - 1, ps, pe+ri-ie-1, postorder);
root->right = dfs_inAndPost(ri + 1, ie, pe + ri - ie, pe - 1, postorder);

北理工复试上机题目

将这两道题结合起来就是2024年北京理工大学计算机专业复试机试最后一道题目,原题目大致题意如下:给出前序、中序输出后序;或者给出中序、后续输出前序遍历。原题目输入的是大写字母,这两道题输入的是数字,不影响解题。

将这两道题目的代码结合起来就是复试最后一道题目的题解:

#include <bits/stdc++.h>

using namespace std;
vector<int> preorder;
vector<int> inorder;
vector<int> postorder;
map<int,int> f;
// 定义二叉树节点结构体
struct TreeNode {
    // 节点存储的整型数值
    int value;

    // 指向左孩子的指针
    TreeNode* left;

    // 指向右孩子的指针
    TreeNode* right;

    // 构造函数
    TreeNode(int val) : value(val), left(nullptr), right(nullptr) {}
};

TreeNode* dfs_inAndpre(int is, int ie, int ps, int pe, vector<int>& preorder) {
    if (is > ie || ps > pe) return nullptr;
    TreeNode* root = new TreeNode(preorder[ps]);
    int ri = f[root->value];
    root->left = dfs_inAndpre(is, ri - 1, ps + 1, ps + ri - is, preorder);
    root->right = dfs_inAndpre(ri + 1, ie, ps + ri - is + 1, pe, preorder);
    return root;
}
TreeNode* dfs_inAndpost(int is, int ie, int ps, int pe, vector<int>& postorder) {
    if (is > ie || ps > pe) return nullptr;
    TreeNode* root = new TreeNode(postorder[pe]);
    int ri = f[root->value];
    root->left = dfs_inAndpost(is, ri - 1, ps, pe+ri-ie-1, postorder);
    root->right = dfs_inAndpost(ri + 1, ie, pe+ri-ie, pe - 1, postorder);
    return root;
}
void printTree_pre(TreeNode* root) {
    if (root == nullptr) return;
    cout << root->value << " ";
    printTree_pre(root->left);
    printTree_pre(root->right);
}
void printTree_post(TreeNode* root) {
    if (root == nullptr) return;
    printTree_post(root->left);
    printTree_post(root->right);
    cout << root->value << " ";
}

int main()
{
    int flag;
    cout << "1、输入中序、前序;2、输入中序、后序;" << endl;
    cin >> flag;
    int n;
    cin >> n;
    if (flag == 1) {
        for (int i = 0; i < n; i++) {
            int temp;
            cin >> temp;
            inorder.push_back(temp);
        }
        for (int i = 0; i < n; i++) {
            int temp;
            cin >> temp;
            preorder.push_back(temp);
        }
        for (int i = 0; i < n; i++) f[inorder[i]] = i;
        TreeNode* root = dfs_inAndpre(0, n - 1, 0, n - 1, preorder);
        printTree_post(root);
    } else {
        for (int i = 0; i < n; i++) {
            int temp;
            cin >> temp;
            inorder.push_back(temp);
        }
        for (int i = 0; i < n; i++) {
            int temp;
            cin >> temp;
            postorder.push_back(temp);
        }
        for (int i = 0; i < n; i++) f[inorder[i]] = i;
        TreeNode* root = dfs_inAndpost(0, n - 1, 0, n - 1, postorder);
        printTree_pre(root);
    }
}

已经忘记当时怎么做的了,只通过了两个测试样例。但是幸亏前都三个题目都ac了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值