leetcode 105. 从前序与中序遍历序列构造二叉树

问题描述

根据一棵树的前序遍历与中序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

代码

/**
 * 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 fun(0,preorder.size()-1,0,inorder.size()-1,preorder,inorder);
    }
    TreeNode* fun(int leftpre,int rightpre,int leftin,int rightin,vector<int>& preorder,vector<int>& inorder)
    {
        if(leftpre > rightpre)return NULL;
        TreeNode* node = new TreeNode(preorder[leftpre]);
        int i;
        for(i = leftin;i <= rightin; ++i)
        {
            if(preorder[leftpre] == inorder[i])
                break;
        }
        int k = i-leftin;
        node->left = fun(leftpre+1,leftpre+k,leftin,i-1,preorder,inorder);
        node->right = fun(leftpre+1+k,rightpre,i+1,rightin,preorder,inorder);
        return node;
    }
};

结果

执行用时 :52 ms, 在所有 C++ 提交中击败了31.30%的用户
内存消耗 :17.3 MB, 在所有 C++ 提交中击败了45.45%的用户

代码2

使用unordered_map代替手工查找提高效率:

/**
 * 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) {
        unordered_map<int,int> table;
        for(int i = 0;i < inorder.size(); ++i)
            table[inorder[i]] = i;
        return fun(0,preorder.size()-1,0,inorder.size()-1,preorder,inorder,table);
    }
    TreeNode* fun(int leftpre,int rightpre,int leftin,int rightin,vector<int>& preorder,vector<int>& inorder,unordered_map<int,int>& table)
    {
        if(leftpre > rightpre)return NULL;
        TreeNode* node = new TreeNode(preorder[leftpre]);
        auto it = table.find(preorder[leftpre]);
        int i = it->second;
        int k = i-leftin;
        node->left = fun(leftpre+1,leftpre+k,leftin,i-1,preorder,inorder,table);
        node->right = fun(leftpre+1+k,rightpre,i+1,rightin,preorder,inorder,table);
        return node;
    }
};

结果

执行用时 :20 ms, 在所有 C++ 提交中击败了89.07%的用户
内存消耗 :17.7 MB, 在所有 C++ 提交中击败了42.42%的用户

代码3(循环实现)

如preorder[7,1,2,3,4,5,…]和inorder[7,5,…,4,…,]可知1的左子节点是2,2的左子节点是3,……,4的左子节点是5。inorder中5和4之间的节点为5的右子树。
因此有如下操作。

/**
 * 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) {
       if(preorder.size()==0)return NULL;
       stack<TreeNode*> st;
       TreeNode* ans = new TreeNode(preorder[0]);
       TreeNode* tmp = NULL;
       st.push(ans);
       int curinorder = 0;
       for(int i = 1; i < preorder.size(); ++i)
       {
           // 如果栈顶元素与中序的当前节点(curorder)不同,则意味着前序的当前节点(i)是栈顶结点的左儿子
           if(st.top()->val != inorder[curinorder])
           {    
               st.top()->left = new TreeNode(preorder[i]);
               st.push(st.top()->left);
               continue;
           }
           // 如果相同,则意味着前序的当前节点(i)是栈中某个元素的右儿子
           while(!st.empty() && st.top()->val == inorder[curinorder])
           {
               tmp = st.top();
               st.pop();
               ++curinorder;
           }
           tmp->right = new TreeNode(preorder[i]);
           st.push(tmp->right);
       }
       return ans;
    }
};

结果

执行用时 :8 ms, 在所有 C++ 提交中击败了99.80%的用户
内存消耗 :17 MB, 在所有 C++ 提交中击败了48.48%的用户
posted @ 2020-06-01 11:29  曲径通霄  阅读(113)  评论(0编辑  收藏  举报