依靠中序遍历和先序(或后序)求解后序(或先序)

题目链接

[NOIP2001]求先序排列https://ac.nowcoder.com/acm/contest/21763/1011

思路

通过先序和中序求后序,与通过后序和中序求先序的方法几乎是一样的思路,只是需要留意先序的遍历顺序是根左右,后序的遍历顺序是左右根即可。
这里我们以后序和中序构建先序为例子来讲讲如何实现。

首先要搞清楚中序遍历和后序遍历的关系。
给出中序遍历序列BADC和后序遍历序列BDCA,我们来看看处理的步骤。\

  1. 记每棵子树(包括待求解树本身)中序遍历中元素位置为[l1, r1],在后序遍历中元素位置为[l2, r2],显然有。通过调用solve(0, inorder.size()-1, 0, inorder.size()-1)进入第一次根结点处理。其中参数列表solve(int l1, int r1, int l2, int r2)
  2. 根据后序遍历的顺序为左右根可以得出当前后序遍历的最后一位一定是树的根结点(这里的当前不仅仅指的是整棵树的后序遍历,每次划分左右子树区间后同样最后一位是子树的根结点)。即当前根结点为A
  3. 在中序遍历中找到根结点(当前为A)对应的下标pos,此时pos=1
  4. 根据中序遍历顺序为左根右,我们可以知道A左侧的所有元素都是在A的左子树上,同理A右侧的所有元素都是在A的右子树上。可以推出A的左子树在中序遍历中元素位置为[l1, pos-1],左子树在后序遍历中元素位置为[l2, l2+pos-1-l1],同理可以推出右子树的元素位置,在此不多赘述。
  5. 找到左子树和右子树的位置之后我们即可通过同样的方式对子树操作,把子树看作是步骤1输入的树,分别处理左右子树逻辑。
  6. 递归完成上述步骤。

不建树代码

不难发现其实在生成根结点->处理左子树->处理右子树的这个过程中就是一个先序遍历的顺序,那么可以在处理过程中直接输出每次生成的根结点的值,这本身就是先序遍历序列。

#include <bits/stdc++.h>
#define int long long

using namespace std;

unordered_map<char, int> mp; // map用来直接存储当前结点在中序遍历中的下标,可以在O(1)的时间查询

string inorder, postorder;

void solve(int l1, int r1, int l2, int r2){
    if (l1 > r1) return;
    char root = postorder[r2];
    cout << root;
    int pos = mp[root];
    solve(l1, pos - 1, l2, l2 + (pos - l1) - 1);
    solve(pos + 1, r1, r2 - r1 + pos, r2 - 1);
}

signed main(){
    ios :: sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    
    cin >> inorder >> postorder;
    for (int i = 0; i < inorder.size(); i++){
        mp[inorder[i]] = i;
    }
    int len = inorder.size();
    solve(0, len - 1, 0, len - 1);
    
    return 0;
}

建树代码

#include <bits/stdc++.h>
#define int long long

using namespace std;

class treeNode{
public:
	int val;
  	treeNode* left;
  	treeNode* right;
  	treeNode(int val){
    	this->val = val;
    	this->left = nullptr;
      	this->right = nullptr;
    }
}* Tree;

unordered_map<char, int> mp;

string inorder, postorder;

Tree solve(int l1, int r1, int l2, int r2){
    if (l1 > r1) return nullptr;
    char root_val = postorder[r2];
  	treeNode * root = new treeNode(root_val);
    int pos = mp[root];
    root->left = solve(l1, pos - 1, l2, l2 + (pos - l1) - 1);
    root->right = solve(pos + 1, r1, r2 - r1 + pos, r2 - 1);
  	return root;
}

signed main(){
    ios :: sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    
    cin >> inorder >> postorder;
    for (int i = 0; i < inorder.size(); i++){
        mp[inorder[i]] = i;
    }
    int len = inorder.size();
    Tree root = solve(0, len - 1, 0, len - 1);
    
    return 0;
}
全部评论

相关推荐

11-14 23:37
已编辑
华南理工大学 C++
#高情商面试官评选#&nbsp;百度一面面试官:虽然因为技术栈不匹配一面就挂了,但是人非常好,很有耐心,当时是应该是我第一次还是第二次面试,很紧张,他给了我很多建议,得知我秋招刚开始之后,又告诉我得好好准备准备。Minimax的一面和二面面试官:全程真的很礼貌,在我回答问题的时候会频频点头表示肯定,你能感受到对方是尽量在保持平等的关系跟你对谈,用的词都是我们先“讨论”一下这个项目,而不是我“问”你几个问题。最差:字节面试官。机械式地问八股,无论答得怎么样没有一点反馈,表情阴沉,完全看不出来任何招人的感觉,项目介绍完没有问任何问题,编程题写完就结束了也没有追问。面完秒挂。更新。最好的面试官+1:TME二面面试官,这不是面试官,是我的理想导师,真的我都怀疑自己是不是在面试了,我答不上来他会循循善诱,给我讲应该怎么做。原来我们是真的能在面试中学到知识的。最后我直言答得不好,他还安慰我已经做得很棒了。反问的时候给我耐心讲了要学习哪些组件,以及每个组件应该学习到哪种程度。最后竟然还说感谢“您”的时间。第二次更新:最好的面试官+1,oppo一面面试官。面试三十多场第一次见到女面试官,之前牛客都说见到女面试官就完蛋了,不过我运气不错。面试官人真的很好,全程和蔼可亲,保持微笑,然后称呼都是“您”,尤其是反问环节,真的讲解的事无巨细,还向我推荐应该读的书。
OfferDaole:我昨天面试货拉拉也遇到了一个非常好的面试官,专业知识,综合素养都非常高。上来先介绍今天面试的流程,分三个部分,说我们分别对这三个部分进行一个讨论。注意!用的是讨论,我都震惊了。然后全程没有问八股,结合面试官提供的代码分析代码的不足,如何修改。在我回答的过程中他没有打断过,在我对有些问题思考时间过长的时候他没有催促我,在我回答的点比较分散时他会帮我总结。全程非常耐心,并且会引导我往哪方面去思考!真的是我的理想导师了
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务