剑指Offer 面试题07. 重建二叉树

解题思路

利用递归分治法重新建立二叉树:
首先,我们先找规律。给定一个二叉树的前序遍历和中序遍历是可以唯一确定一颗二叉树的,怎么建呢?
先序遍历,每次都首先遍历根节点,那么好了,每一次我们在先序序列中的元素都是某子树的根节点,整个先序序列的第一个元素就是整个二叉树的根元素

既然根元素确定了,就需要知道根元素的左子树和右子树都有哪些,怎么确定呢?就要去中序序列中找,如下如所示:
在这里插入图片描述
当我们的根节点确定了是3之后,要去中序遍历中找以3为根节点的左右子树,中序遍历的顺序是:左子树、根、右子树,所以当我们在中序序列中找到3之后,自然左面的都是左子树,右面的都是右子树,这样一直递归重建,就得到我们想要的结果了。

源代码:

class Solution {
public:
    TreeNode* helper(vector<int>& preorder,int p_b,int p_e,vector<int>& inorder, int i_b,int i_e){
        //初始化当前的根节点
        TreeNode *root = new TreeNode(preorder[p_b]);
        root->left = NULL;
        root->right = NULL;
        //这里是要在中序序列中找到根节点
        int i = i_b;
        while(i < i_e && inorder[i] != preorder[p_b]) i++;
        //这里要记录左右子树长度,如果某一面没有,就没必要再去递归建立
        int i_l_len = i-i_b, i_r_len=i_e-i;
        if(i_l_len > 0){
            /* 
			每次建立,中序序列的起点和终点以及前序序列的起点和终点
			都不太一样。
			前序序列中,下一个元素就是我们左子树重建的根节点,而到哪里结束呢?
			就是起点加上左子树的个数。
			右子树同理,前序序列中,左子树起点加上左孩子个数加1,
			就是右子树的新起点,而原来的前序终点就是新终点;
			中序遍历就很好确定了,以当前根节点索引为界限(也就是i)
			左子树就是原中序起点到i-1,
			右子树就是i+1到原中序终点
            **/
            root->left = helper(preorder,p_b+1,p_b+i_l_len,inorder,i_b,i-1);
        }
        if(i_r_len > 0){
            root->right = helper(preorder,p_b+i_l_len+1,p_e,inorder,i+1,i_e);
        }
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.size() <= 0 || inorder.size() <= 0) return NULL;
        return helper(preorder,0,preorder.size()-1,inorder,0,inorder.size()-1);
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章