题目链接:

https://ac.nowcoder.com/acm/problem/204382

题面:

给定一棵有n个结点的二叉树的先序遍历与后序遍历序列,求其中序遍历序列。 若某节点只有一个子结点,则此处将其看作左儿子结点(示意图和样例见题) 1≤n≤100,000

代码+解析:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int 二叉树节点数量
     * @param pre intvector 前序序列
     * @param suf intvector 后序序列
     * @return i  ntvector
     */
    
    vector<int> zhong;
    
    void deal(int pre_l, int pre_r, int suf_l, int suf_r, vector<int>& pre, vector<int>& suf) {
        
        if (pre_l > pre_r) {  
            return ;   
        }
        
        if (pre_l == pre_r) {    // 子树递归出口
            zhong.push_back(pre[pre_l]);    // 若某节点只有一个子结点,则此处将其看作左儿子结点,恰好中序遍历是:左-根-右,先遍历左子树
            return ;   
        }        
        
        int next_root = pre[pre_l+1];
        
        // 前序遍历子序列的当前根节点 pre[pre_l] 对应的位置的下一个数 next_root 是 下一棵子树的根, 
        // 而 这个下一棵子树是左子树还是右子树 取决于 下一棵子树的根在后序遍历子序列的划分 (suf[ptr_suf] == next_root) (下下棵子树的左子树的最右侧节点)
        
        int ptr_suf = suf_l;
        for (; ptr_suf <= suf_r; ptr_suf++) {
            if (suf[ptr_suf] == next_root) {  
                break;
            }
        }
        
        // 左子树
        deal(pre_l + 1, pre_l + 1 + (ptr_suf - suf_l), suf_l, ptr_suf, pre, suf);
        
        // 当前 根
        zhong.push_back(pre[pre_l]);
        
        // 右子树
        deal(pre_r - ((suf_r - 1) - (ptr_suf + 1)), pre_r, ptr_suf + 1, suf_r - 1, pre, suf);
                            
    }
    
    
    
    vector<int> solve(int n, vector<int>& pre, vector<int>& suf) {
        // write code here
        // 若只已知 前序遍历序列 和 后序遍历序列,条件强度是不够的解题的。因为前序:根-左-右,后序:左-右-根。每颗子树的根都好确定,不能分清左右子树
        // 题目强化条件:若某节点只有一个子结点,则此处将其看作左儿子结点,这样就可以利用其衍生的叶子节点无左右子树等特征来划分。
        
        deal(0, n-1, 0, n-1, pre, suf);
        
        return zhong;

    }
};