每天一道LeetCode-----根据先序遍历和中序遍历还原二叉树

Construct Binary Tree from Preorder and Inorder Traversal

原题链接Construct Binary Tree from Preorder and Inorder Traversal

这里写图片描述

给定一个二叉树的先序遍历和中序遍历,要求重现这棵二叉树

另先序遍历的序列为preorder,中序遍历的序列为inorder,节点个数为n

根据先序遍历的特点,可知preorder[0]一定是整棵二叉树的根节点,那么,如果已确定根节点值在中序遍历序列inorder中的下标是i,就一定有

  • inorder[0 : i - 1]这些值属于根节点的左子树
  • inorder[i + 1, n - 1]这些值属于根节点的右子树

因为中序遍历是从最左边开始遍历,所以当遍历到根节点inorder[i]时,之前遍历到的节点一定都属于左子树

那么现在的目的就是如何确定左右子树的根节点,由先序遍历可知

  • preorder[0 + 1]一定是左子树的根节点
  • preorder[0 + 1 + (i - 0)]一定是右子树的根节点

因为先序遍历遍历到的节点顺序是从根节点到最左边,再到右边,那么既然已经直到左子树上有多少节点了(i - 0个),那么就可以确定右子树的根节点

直接递归即可

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return buildTree(0, 0, inorder.size() - 1, preorder, inorder);  
    }
private:
    /* preStart : 当前根节点在preorder中的下标
     * [inStart:inEnd]  : 以preorder[preStart]为根节点的子树的节点值在inorder的范围
     */
    TreeNode* buildTree(int preStart, int inStart, int inEnd, vector<int>& preorder, vector<int>& inorder)
    {
        if(preStart >= preorder.size() || inStart > inEnd)
            return nullptr;

        /* 申请根节点 */
        TreeNode* root = new TreeNode(preorder[preStart]);
        /* 寻找根节点在inorder的位置,拆分左右子树 */
        int inIndex = 0;
        for(int i = inStart; i <= inEnd; ++i)
        {
            if(inorder[i] == preorder[preStart])
            {
                inIndex = i;
                break;
            }
        }

        root->left = buildTree(preStart + 1, inStart, inIndex - 1, preorder, inorder);
        root->right = buildTree(preStart + 1 + inIndex - inStart, inIndex + 1, inEnd, preorder, inorder);
        return root;
    }
};

本题主要需要弄清楚如何进行递归,当然拆分成左右子树是个很好的方法,不够不太容易想到。

先序遍历可以直到根节点,而中序遍历可以确定该根节点的左右子树的取值范围,从而不断拆分下去,最终求解

你可能感兴趣的:(LeetCode)