代码随想录书体攻略--二叉树3--二叉树的修改与构造

进入第3节:二叉树的修改与构造

例题1:翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

这题很简单,前序遍历和后序遍历都能做, 即先翻转根结点还是先翻转左右结点都可以;但是中序遍历的话,某些节点的左右孩子会翻转两次。

后序遍历代码:

class Solution {
public:
    void invert(TreeNode* root)
    {
        if(root == NULL)//终止条件
            return;
        invert(root->left);//左
        invert(root->right);//右
        swap(root->left,root->right);//根
    }

    TreeNode* invertTree(TreeNode* root) {
        invert(root);
        return root;
    }
};

例题2:从中序与后序遍历序列构造二叉树

 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

 

由中序遍历和后序遍历构造一颗树, 数据结构课的时候会教解决流程,先找出根结点,再划分其左右子树的数组,并把然后递归地去找左右子树中的根结点和左右子树....将上一层的根节点与本层的左右子树通过 left, right指针联系起来。

此时应该注意确定切割的标准,是左闭右开,还有左开右闭,还是左闭右闭,这个就是不变量,要在递归中保持这个不变量。

终止条件:

若中序遍历数组为空,返回NULL;

单层处理逻辑:

  • 第一步:如果数组大小为零的话,说明是空节点了。

  • 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。

  • 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点

  • 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)

  • 第五步:切割后序数组,切成后序左数组和后序右数组

  • 第六步:递归处理左区间和右区间

class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        //终止条件
        if(inorder.size() == 0) return nullptr;//inorder和postorder是一样长的,判断一个数组酒啊后二零

        //对于两个数组,先划分出根,左子树,右子树
        int mid = postorder[postorder.size()-1];
        TreeNode *root = new TreeNode(mid);
        
        int i = 0;
        for(i; i < inorder.size(); i++)
        {
            if(inorder[i] == mid)
                break;
        }
        //获得了mid在中序遍历数组中的位置 而且是左闭右开区间

        //切割中序数组
        vector<int> linorder(inorder.begin(), inorder.begin() + i);
        vector<int> rinorder(inorder.begin() + i + 1, inorder.end());

        //切割后序数组
        //postorder.resize(postorder.size() - 1);
        vector<int> lpostorder(postorder.begin(), postorder.begin() + linorder.size());
        vector<int> rpostorder(postorder.begin() + linorder.size(), postorder.end()-1);

        root -> left = buildTree(linorder,lpostorder);
        root-> right = buildTree(rinorder,rpostorder);
        return root;
    }

例题3:最大二叉树

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:

  1. 创建一个根节点,其值为 nums 中的最大值。
  2. 递归地在最大值 左边 的 子数组前缀上 构建左子树。
  3. 递归地在最大值 右边 的 子数组后缀上 构建右子树。

返回 nums 构建的 最大二叉树 

跟上一题很相似,可以写出代码如下:

class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        if(nums.size() == 0) return NULL;

        int max = -1;
        int maxpos = 0;
        for(int i = 0; i < nums.size(); i++)
        {
            if (nums[i] > max)
            {
                maxpos = i;
                max = nums[i];
            }
        }

        TreeNode *root = new TreeNode(max);
        vector<int> lsub(nums.begin(), nums.begin() + maxpos);
        vector<int> rsub(nums.begin() + maxpos + 1, nums.end());

        root -> left = constructMaximumBinaryTree(lsub);
        root -> right = constructMaximumBinaryTree(rsub);

        return root;
    }
    //第一步 找出数组中的最大值 作为根结点
    //第二步 将数组分为左子数组和右子数组,递归建树。
    //将根结点与左右子树连接
};

代码随想录里还有其他的解法,我们上述的代码在每一层中都要定义一个新的数组,其实可以用类似于数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下标索引直接在原数组上操作,可以节约时间和空间上的开销

class Solution {
private:
    // 在左闭右开区间[left, right),构造二叉树
    TreeNode* traversal(vector<int>& nums, int left, int right) {
        if (left >= right) return nullptr;

        // 分割点下标:maxValueIndex
        int maxValueIndex = left;
        for (int i = left + 1; i < right; ++i) {
            if (nums[i] > nums[maxValueIndex]) maxValueIndex = i;
        }

        TreeNode* root = new TreeNode(nums[maxValueIndex]);

        // 左闭右开:[left, maxValueIndex)
        root->left = traversal(nums, left, maxValueIndex);

        // 左闭右开:[maxValueIndex + 1, right)
        root->right = traversal(nums, maxValueIndex + 1, right);

        return root;
    }
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return traversal(nums, 0, nums.size());
    }
};

例题4:合并二叉树

给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

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;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值