【精选高频面试题】-二叉树的修改与构造系列

二叉树的修改与构造

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

105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode) (leetcode-cn.com)

给定一棵树的前序遍历 preorder 与中序遍历 inorder。请构造二叉树并返回其根节点。

Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]

思路:这道题的思路为分割数组。我们发现前序遍历中数组的第一个值为根节点。在中序数组中找到这个值,将他们分为左中序数组,右中序数组,再对前序的数组也进行分割。知道分割到叶子节点便返回

class Solution {
public:
    TreeNode* trval(vector<int>&preorder,int preorderbegin,int preorderend,vector<int>&inorder,int inorderbegin,int inorderend){
        //中序数组为空,返回空
        if(preorderend-preorderbegin==0)return NULL;
        //获取根节点的值,并构造一个根节点
        int rootvalue=preorder[preorderbegin];
        TreeNode* root=new TreeNode(rootvalue);
        //如果这个数组中只有一个节点那么,这个节点就是叶子节点,并返回
        if(preorderend-preorderbegin==1)return root;
        //在中序数组中找到分割点,并将其分割
        int qgpointval=inorderbegin;
        for(;qgpointval<inorderend;qgpointval++){
            if(inorder[qgpointval]==rootvalue)break;
        }
        //获得左中序,右中序的下表值
        int leftinorderbegin=inorderbegin;
        int leftinorderend=qgpointval;

        int rightinorderbegin=qgpointval+1;
        int rightinorderend=inorderend;

        //当我们获取了分割后的中序下表,我们就可以获取前序的下表(中序与前序分割后的数组大小相等)
        int leftpreorderbegin=preorderbegin+1;
        int leftpreorderend=preorderbegin+1+qgpointval-inorderbegin;

        int rightpreorderbegin=preorderbegin+1+qgpointval-inorderbegin;
        int rightpreorderend=preorderend;
        //遍历循环
        root->left=trval(preorder,leftpreorderbegin,leftpreorderend,inorder,leftinorderbegin,leftinorderend);
        root->right=trval(preorder,rightpreorderbegin,rightpreorderend,inorder,rightinorderbegin,rightinorderend);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
           if(preorder.size()==0||inorder.size()==0)return NULL;
           return trval(preorder,0,preorder.size(),inorder,0,inorder.size());
    }
};

Leetcode.106.从后序与中序遍历序列构造二叉树

106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode) (leetcode-cn.com)

思路:后续的思路与前序的差不多,只不过是根节点是后序数组的最后一个

代码直接给出

class Solution {
public:
    TreeNode* trval(vector<int>&inorder,int inorderbegin,int inorderend,vector<int>&postorder,int postorderbegin,int postorderend){
        if(postorderbegin==postorderend)return NULL;
        int qgvalue=postorder[postorderend-1];
        TreeNode* root=new TreeNode(qgvalue);
        if(postorderend-postorderbegin==1)return root;

        int qgpoint;
        for(qgpoint=0;qgpoint<inorderend;qgpoint++){
            if(inorder[qgpoint]==qgvalue)break;
        }
        int leftinorderbegin=inorderbegin;
        int leftinorderend=qgpoint;

        int rightinorderbegin=qgpoint+1;
        int rightinorderend=inorderend;
          
        int leftpostorderbegin=postorderbegin;
        int leftpostorderend=postorderbegin+qgpoint-inorderbegin;

        int rightpostorderbegin=postorderbegin+(qgpoint-inorderbegin);
        int rightpostorderend=postorderend-1;
        
        root->left=trval(inorder,leftinorderbegin,leftinorderend,postorder,leftpostorderbegin,leftpostorderend);
        root->right=trval(inorder,rightinorderbegin,rightinorderend,postorder,rightpostorderbegin,rightpostorderend);
        return root;

    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
           if(inorder.size()==0||postorder.size()==0)return NULL;
           return trval(inorder,0,inorder.size(),postorder,0,postorder.size());
    }
};

Leetcode.654.最大二叉树

654. 最大二叉树 - 力扣(LeetCode) (leetcode-cn.com)

给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:

二叉树的根是数组 nums 中的最大元素。
左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。
右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。
返回有给定数组 nums 构建的 最大二叉树 。

输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]
解释:递归调用如下所示:
- [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。
    - [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
        - 空数组,无子节点。
        - [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。
            - 空数组,无子节点。
            - 只有一个元素,所以子节点是一个值为 1 的节点。
    - [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。
        - 只有一个元素,所以子节点是一个值为 0 的节点。
        - 空数组,无子节点。

思路:这道题思路与上一题的思路差不多。分割数组的思想的运用。我们首先在数组找到最大值作为根节点。根节点之前的数组为左数组用来构建左二叉树,同理右边的用来构建右二叉树

我们采用递归的思路

第一:确定返回类型为TreeNode.参数为数组。由于我们要分割数组,所以我们要设置一个左右标记符,用来结束递归

TreeNode* trval(vector< int >&vec,int left,int right);

第二:终止条件:当left>=right时即数组中只还有一个值时

第三:单层遍历逻辑:我们首先要在数组里面找到最大值作为根节点,然后继续递归获取根节点的左右节点

class Solution {
public:
    TreeNode* trval(vector<int>&nums,int left,int right){
        //终止条件 
        if(left>=right)return NULL;
        //寻找最大值,并记录其下表
        int maxvalueindex=left;
        for(int i=left+1;i<right;i++){
            if(nums[i]>nums[maxvalueindex]){
                maxvalueindex=i;
            }
        }
        //构建节点
        TreeNode* root=new TreeNode(nums[maxvalueindex]);
        //递归构建
        root->left=trval(nums,left,maxvalueindex);
        root->right=trval(nums,maxvalueindex+1,right);
        return root;
    }
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
               return trval(nums,0,nums.size());
    }
};

Leetcode.617.合并二叉树

617. 合并二叉树 - 力扣(LeetCode) (leetcode-cn.com)

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。

你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

示例 1:

输入:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
输出:
合并后的树:
3
/
4 5
/ \ \
5 4 7
注意: 合并必须从两个树的根节点开始

思路:我们采用递归的方式来做这道题。这道题的主要解决问题就是遍历两颗树。我们以一棵树为基本树,在其上面进行修改。

第一:确定返回类型:TreeNode* 参数:由于我们要遍历两颗树那么就是传入两棵树的根节点

第二:终止条件:当一个节点为空时返回另一个节点,另一个节点 为空也没关系,都返回空,两个节点值相加也为空

第三:单层遍历逻辑:就是把第二课树的值赋给第一颗树

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
      //终止条件
        if(root1==NULL)return root2;
        if(root2==NULL)return root1;
         root1->val+=root2->val;
        root1->left=mergeTrees(root1->left,root2->left);
        root1->right=mergeTrees(root1->right,root2->right);
        return root1;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值