[LeetCode]Construct Binary Tree from Preorder and Inorder Traversal

Posted 乘风有时

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[LeetCode]Construct Binary Tree from Preorder and Inorder Traversal相关的知识,希望对你有一定的参考价值。

105. Construct Binary Tree from Preorder and Inorder Traversal

Given preorder and inorder traversal of a tree, construct the binary tree.

Note:
You may assume that duplicates do not exist in the tree.

题意;给定前序和中序遍历的序列,构造该二叉树

思路:

前序遍历的序列中每个元素都是一颗子树的根节点,从根节点开始到它的左子树的根节点...

而中序遍历的序列是被根节点分成了前后两部分,前面一半是左子树,后面一半是右子树;

因此,可以以前序序列中的元素为中心来划分中序序列。

例如:

前序遍历:1->2->4->5->3->6->8->7

前序序列中1时整棵树的树根,2是1的左子树的树根,4是2的左子树的树根,5是2的右子树的树根,3是1的右子树的树根......

中序遍历:4->2->5->1->8->6->3->7

中序序列中树根1将其分成{4,2,5}和{8,6,3,7},{4,2,5}正是1的左子树中的节点,{8,6,3,7}正是1的右子树中的节点;

同样2将{4,2,5}分成两部分,正好对应它的左右子树的节点,因此,可以将两个序列结合起来确定二叉树的结构。

 

递归的做法

prePos表示当前元素在前序序列中的位置下标;border是中序序列中的一个范围下标,它是当前子树在中序序列中的范围。

prePos = 1,即指向元素2时,border = [0,2],即包含[4,2,5]三个元素;

prePos = 5,即指向元素6时,border = [4,5],即包含[8,6]两个元素。

TreeNode* recursiveBuildTree(vector<int>& preorder, vector<int>& inorder, int& prePos, pair<int, int> border){
    //空的情况
    if (!inorder.size())return NULL;
    //避免无左右子树,导致下届比上届还大
    if (border.first > border.second)return NULL;
    if (border.first == border.second){//只剩唯一元素
        TreeNode *root = new TreeNode(inorder.at(border.first));
        return root;
    }
    //生成当前根节点
    TreeNode *root = new TreeNode(preorder.at(prePos));
    int middle = border.first;
    //找到当前根节点在中序遍历中的位置,将它以根节点为界分为左右子树
    while (middle <= border.second && preorder.at(prePos) != inorder.at(middle)){
        middle++;
    }
    pair<int, int>cborder(border.first,middle - 1);//左子树的范围
    root->left = recursiveBuildTree(preorder, inorder, ++prePos, cborder);//寻找左子树
    if (root->left == NULL)prePos--;//若左子树为空,则prePos不应该加一
    cborder.first = middle + 1;
    cborder.second = border.second;
    root->right = recursiveBuildTree(preorder, inorder, ++prePos, cborder);//寻找右子树
    if (root->right == NULL)prePos--;//右子树为空时,prePos不应该加一
    return root;
}

非递归的解法

TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    //空树的情况
    if (!inorder.size())return NULL;
    TreeNode* root = new TreeNode(preorder.at(0));
    stack<pair<TreeNode*,pair<int,int>>>s;
    int prei = 0;//当前访问的元素在前序序列中的位置
    pair<int, int>border(0,inorder.size() - 1);//当前元素对应在中序序列中的范围
    pair<TreeNode*, pair<int, int>> e0(root,border);
    s.push(e0);
    while (!s.empty()){
        pair<TreeNode*, pair<int, int>> p = s.top();
        int middle = p.second.first;
        //找到当前根节点在中序遍历中的位置,将它以根节点为界分为左右子树
        while (middle <= p.second.second && p.first->val != inorder.at(middle)){
            middle++;
        }
        //没有找到,序列有错,无法得到二叉树
        if (middle > p.second.second)return NULL;
        //左子树为空或为叶节点,或左子树已访问过
        if (middle - 1 <= p.second.first || p.first->left != NULL){
            if (p.first->left == NULL && middle - 1 == p.second.first){//左子树是叶节点
                ++prei;
                TreeNode* left = new TreeNode(inorder.at(middle - 1));
                p.first->left = left;
            }
            s.pop();
            if (middle + 1 == p.second.second){//右子树是叶节点
                ++prei;
                TreeNode* right = new TreeNode(inorder.at(middle + 1));
                p.first->right = right;
            }
            else if (middle + 1 < p.second.second){//进入右子树
                ++prei;
                pair<int, int>rightBorder(middle + 1, p.second.second);
                TreeNode* right = new TreeNode(preorder.at(prei));
                p.first->right = right;
                pair<TreeNode*, pair<int, int>> rightNode(right, rightBorder);
                s.push(rightNode);
            }
        }else{//进入左子树
            ++prei;
            pair<int, int>leftBorder(p.second.first,middle - 1);
            TreeNode* left = new TreeNode(preorder.at(prei));
            p.first->left = left;
            pair<TreeNode*, pair<int, int>> leftNode(left,leftBorder);
            s.push(leftNode);
        }
    }
    return root;
}

 

106 Construct Binary Tree from Inorder and Postorder Traversal

Given inorder and postorder traversal of a tree, construct the binary tree.

Note:
You may assume that duplicates do not exist in the tree.

题意:给定中序和后序遍历的序列,构造该二叉树

和上面的类似,后序序列是左子树、右子树、树根的顺序遍历,因此,树根必然是最后的一个元素,接着从后往前是右子树、左子树...

因此和前序相反,再结合中序就能确定树的结构。

例如:(还是上面的二叉树)

中序遍历:4->2->5->1->8->6->3->7

后序遍历:4->5->2->8->6->7->3->1

后序序列中最后的一定是树根节点1,然后3是1的右子树的树根,7是3的右子树的树根,6是3的左子树树根,8是6的儿子节点,这个是左孩子还是右孩子要根据中序的序列来确认;

例如如果中序中8在6的前面,则8是6的左孩子;反之则是6的右孩子。

因此,同理能够通过中序和后序序列的到二叉树的结构。

 

递归的做法

TreeNode* recursiveBuildTree(vector<int>& inorder, vector<int>& postorder, int& postPos, pair<int, int> border){
    //空的情况
    if (!inorder.size())return NULL;
    //避免无左右子树,导致下界比上界还大
    if (border.first > border.second)return NULL;
    if (border.first == border.second){//只剩唯一元素
        TreeNode *root = new TreeNode(inorder.at(border.first));
        return root;
    }
    //生成当前根节点
    TreeNode *root = new TreeNode(postorder.at(postPos));
    int middle = border.first;
    //找到当前根节点在中序遍历中的位置,将它以根节点为界分为左右子树
    while (middle <= border.second && postorder.at(postPos) != inorder.at(middle)){
        middle++;
    }
    pair<int, int>cborder(middle + 1, border.second);//右子树的范围
    root->right = recursiveBuildTree(inorder, postorder, --postPos, cborder);//寻找右子树
    if (root->right == NULL)postPos++;//若右子树为空,则postPos不应该减一
    cborder.first = border.first;
    cborder.second = middle - 1;
    root->left = recursiveBuildTree(inorder, postorder, --postPos, cborder);//寻找左子树
    if (root->left == NULL)postPos++;//左子树为空时,postPos不应该减一
    return root;
}

非递归的做法

TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder){
    //空树的情况
    if (!inorder.size())return NULL;
    int prei = postorder.size() - 1;//当前访问的元素在后序序列中的位置
    TreeNode* root = new TreeNode(postorder.at(prei));
    stack<pair<TreeNode*, pair<int, int>>>s;
    pair<int, int>border(0, inorder.size() - 1);//当前元素对应在中序序列中的范围
    pair<TreeNode*, pair<int, int>> e0(root, border);
    s.push(e0);
    while (!s.empty()){
        pair<TreeNode*, pair<int, int>> p = s.top();
        int middle = p.second.first;
        //找到当前根节点在中序遍历中的位置,将它以根节点为界分为左右子树
        while (middle <= p.second.second && p.first->val != inorder.at(middle)){
            middle++;
        }
        //没有找到,序列有错,无法得到二叉树
        if (middle > p.second.second)return NULL;
        //右子树为空或为叶节点,或右子树已访问过
        if (middle + 1 >= p.second.second || p.first->right != NULL){
            if (p.first->right == NULL && middle + 1 == p.second.second){//右子树是叶节点
                --prei;
                TreeNode* right = new TreeNode(inorder.at(middle + 1));
                p.first->right = right;
            }
            s.pop();
            if (middle - 1 == p.second.first){//左子树是叶节点
                --prei;
                TreeNode* left = new TreeNode(inorder.at(middle - 1));
                p.first->left = left;
            }
            else if (middle - 1 > p.second.first){//进入左子树
                --prei;
                pair<int, int>leftBorder(p.second.first, middle - 1);
                TreeNode* left = new TreeNode(postorder.at(prei));
                p.first->left = left;
                pair<TreeNode*, pair<int, int>> leftNode(left, leftBorder);
                s.push(leftNode);
            }
        }
        else{//进入右子树
            --prei;
            pair<int, int>rightBorder(middle + 1, p.second.second);
            TreeNode* right = new TreeNode(postorder.at(prei));
            p.first->right = right;
            pair<TreeNode*, pair<int, int>> rightNode(right, rightBorder);
            s.push(rightNode);
        }
    }
    return root;
}

 

以上是关于[LeetCode]Construct Binary Tree from Preorder and Inorder Traversal的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 236.lowest-common-ancestor-of-a-binary-tr

LeetCode 236.lowest-common-ancestor-of-a-binary-tree

LeetCode Construct the Rectangle

[LeetCode&Python] Problem 492. Construct the Rectangle

[LeetCode&Python] Problem 427. Construct Quad Tree

LeetCode Construct String from Binary Tree