【剑指Offer】面试题6:重建二叉树

整理自剑指Offer和牛客网的讨论 https://www.nowcoder.com/questionTerminal/8b3b95850edb4115918ecebdf1b4d222


一:题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。


二:解题思路

在二叉树的前序遍历中,第一个数总数根节点的值。但在中序遍历中,根节点的值在序列的中间,左子树的结点的值位于根节点的的值得左边,而右子树的结点的值位于根节点的右边,因此我们需要扫描中序遍历序列,才能找到根节点的值。

以例子说明:

如图所示,前序遍历第一个数字1就是根节点的值。扫描中序遍历序列,就能确定根节点值得位置。根据中序遍历的特点,在根节点的值1前面的3个数字都是左子树结点的值,位于1后面的数字都是右子树结点的值。

由于在中序遍历中有3个数字都是左子树结点的值,因此左子树总共有3个左子结点。同样在前序遍历的序列中,根节点后面的3个数字就是3个左子树结点的值。再后面的所有数字都是右子树结点的值。这样我们就在前序遍历和中序遍历中,分别找到了左右子树对应的子序列。


接下来就可以在左子树对应的先序与中序序列中递归调用函数找到当前节点的左结点,右子树对应的先序和中序序列中递归调用函数找到当前节点的有结点


总结方法的步骤(递归):

1.前序遍历序列第一个值是根节点,创建根节点

2.在中序遍历序列中找到根节点位置(根据中序遍历中根节点的位置,可以获得左右子树的大小)

3.计算左子树前序遍历序列的起始终止位置,中序遍历序列的起始终止位置

4.计算右子树前序遍历序列的启示终止位置,中序遍历序列的起始终止位置


例如

先序遍历序列pre

起始位置startPre

终止位置endPre


中序遍历序列vin

起始位置startVin

终止位置endVin


根节点位于中序遍历序列第i个位置,则左子树的长度为(i-startVin),右子树长度(endVin-i)

所以:

左子树:

先序遍历    起始:startPre+1  终止:startPre+i-startVin

中序遍历   起始:startVin     终止:i-1


右子树:

先序遍历  起始:startPre+i-startVin+1(左子树终止+1)   终止 endPre

中序遍历  起始:i+1    终止 endVin


三:代码实现

	/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* reConstructBinaryTreeCore(vector<int> pre,int startPre,int endPre,vector<int> vin,int startVin,int endVin){
        if(startPre>endPre || startVin>endVin)
            return NULL;
        
        //创建当前根结点
        TreeNode* root=new TreeNode(pre[startPre]);
        
        //在中序遍历中找到根结点
        for(int i=startVin;i<=endVin;i++)
            if(vin[i]==pre[startPre]){
                //重新计算左子树pre-startPre,endPre     vin--startVin.endVin
                root->left=reConstructBinaryTreeCore(pre,startPre+1,startPre+i-startVin,vin,startVin,i-1);
                //重新计算右子树pre-startPre,endPre     vin--startVin.endVin
                root->right=reConstructBinaryTreeCore(pre,i-startVin+startPre+1,endPre,vin,i+1,endVin);
                //这种方法很巧妙,不用定义额外的变量存放左右子树中序,先序的信息
            }
        return root;
    }
    
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
		if(pre.size()==0 || vin.size()==0)
            return NULL ;
        TreeNode* root=reConstructBinaryTreeCore(pre,0,pre.size()-1,vin,0,vin.size()-1);
        
        return root;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉树的中序线索化是将二叉树中的每个节点都向其中序遍历的前驱和后继节点。这个过程需要对二叉树进行中序遍历,并将每个节点的左右针修改为向其前驱和后继节点。下面是中序线索化的实现代码: ```python class Node: def __init__(self, val, left=None, right=None): self.val = val self.left = left self.right = right self.left_thread = None self.right_thread = None def inorder_threading(root): if root is None: return stack = [] cur = root pre = None while cur or stack: while cur: stack.append(cur) cur = cur.left cur = stack.pop() if cur.left is None: cur.left = pre cur.left_thread = True if pre and pre.right is None: pre.right = cur pre.right_thread = True pre = cur cur = cur.right if not cur.right_thread else None if __name__ == '__main__': root = Node(1, Node(2), Node(3)) inorder_threading(root) print(root.left.val) # 2 print(root.left.right) # 1 print(root.left.right_thread) # True print(root.right.left) # 1 print(root.right.left_thread) # True print(root.right.val) # 3 ``` 上面的代码中,我们定义了一个 `Node` 类表示二叉树的节点。`left_thread` 和 `right_thread` 分别表示当前节点的左右针是否是线索。初始时,二叉树的所有节点的 `left_thread` 和 `right_thread` 都是 `None`。 `inorder_threading` 函数实现了中序线索化的过程。我们使用一个栈来辅助进行中序遍历。对于每个节点,如果其左子节点为空,则将其左向其中序遍历的前驱节点,并将 `left_thread` 标记为 `True`。如果其前驱节点的右针为空,则将其右向当前节点,并将 `right_thread` 标记为 `True`。 最后,我们可以验证中序线索化的结果是否正确。在上面的代码中,我们打印了一些节点的值和线索情况。可以看到,对于一个节点,其左向的是其中序遍历的前驱节点,而右针则向其中序遍历的后继节点。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值