前序中序遍历序列构造二叉树

链接

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if (preorder.size() == 0) return nullptr;
        int val = preorder[0];
        vector<int> tempinorder_left;
        vector<int> temppreorder_left;
        vector<int> tempinorder_right;
        vector<int> temppreorder_right;
        for (int index = 0; index < inorder.size(); ++index) {
            if (inorder[index] == val) {
                for (int j = index + 1; j < inorder.size(); ++j) {
                    tempinorder_right.push_back(inorder[j]);
                    temppreorder_right.push_back(preorder[j]);
                }
                break;
            } else {
                tempinorder_left.push_back(inorder[index]);
                temppreorder_left.push_back(preorder[index + 1]);
            }
        }
        TreeNode *node = new TreeNode(val);
        node->left = buildTree(temppreorder_left, tempinorder_left);
        node->right = buildTree(temppreorder_right, tempinorder_right);
        return node;
    }
};

思路

最直观的方法,前序序列中的第一个为根节点,然后进行处理(创建两组前序、中序序列),将对应元素复制进去,分别递归;
但是开辟了额外的数组,时空效率极差;

解决方法:
使用两组游标标记两个端点,在递归中修改;

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return MybuildTree(preorder, 0, preorder.size()-1, inorder, 0, inorder.size()-1);
    }

    TreeNode* MybuildTree(vector<int>& preorder, int pl, int pr, vector<int>& inorder, int il, int ir) {
        if (pl > pr) return nullptr;
        int val = preorder[pl];
        int index = il;
        while (inorder[index] != val) {
            ++index;
        }

        TreeNode *node = new TreeNode(val);
        node->left = MybuildTree(preorder, pl+1, pl+index-il, inorder, il, index-1);
        node->right = MybuildTree(preorder, pl+index-il+1, pr, inorder, index+1, ir);
        return node;
    } 
};

要点

每次递归,得到节点为preorder[pl],并找到相应的中序遍历的下标位置(从il开始遍历);
找到小标之后,更新递归中的前、中序的左、右边界
——这里中序可以用index标识位置,前序需要用index-il作为偏移量标识位置(比较烧脑)

————————

还有一种只需要遍历一遍就得到结果的,把in、pre游标作为全局变量,每次递归的时候进行修改;用一个stop值(即preorder[pre]的值)指示每次递归的左右部分;

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int pre = 0;
    int in = 0;

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return MybuildTree(preorder, inorder, INT_MAX);
    }

    TreeNode* MybuildTree(vector<int>& preorder, vector<int>& inorder, int stop) {
        if (pre == preorder.size()) {
            return nullptr;
        }
        if (inorder[in] == stop) {
            ++in;
            return nullptr;
        }

        int val = preorder[pre++];
        TreeNode *node = new TreeNode(val);
        node->left = MybuildTree(preorder, inorder, val);
        node->right = MybuildTree(preorder, inorder, stop);
        return node;
    } 
};

pre、in为全局变量游标;
stop值为preorder[pre]值,也是inorder中分开左右子树的值;若inorder[in]为stop,说明该层递归左子树遍历完了,return null;该层右子树的stop值,是前一层的stop值;

INT_MAX——C++中的整型最大值;
该种方法必须确保树中的任意两个节点的值不相等;

真神仙解法,不多说了。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值