代码随想录算法训练营第二十三天 | 669.修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树、二叉树总结

669.修剪二叉搜索树

题目

给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案

所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。

示例 1:

输入:root = [1,0,2], low = 1, high = 2
输出:[1,null,2]

在这里插入图片描述

提示:

  • 树中节点数在范围 [1, 10(4)]

  • 0 <= Node.val <= 10(4)

  • 树中每个节点的值都是 唯一

  • 题目数据保证输入是一棵有效的二叉搜索树

  • 0 <= low <= high <= 10(4)

思路

在这里插入图片描述

在上图中,发现节点 0 并不符合区间要求,那么将节点 0 的右孩子节点 2 直接赋给节点 3 的左孩子就可以(即把节点 0 从二叉树中移除)

在这里插入图片描述

递归三部曲:

  • 确定递归函数的参数和返回值

    • 遍历整棵树做修改,最后返回 TreeNode*
    • 传入根节点和 low, high
  • 确定终止条件

    • 修剪的操作并不是在终止条件上进行的,所以是遇到空节点返回就可以了
  • 确定单层递归逻辑

    • 如果 root(当前节点)的元素小于 low 的数值,递归右子树,并返回右子树符合条件的头节点
    • 如果 root 元素大于 high,递归左子树,并返回左子树符合条件的头节点
    • 将下一层处理完左子树的结果赋给 root->left,处理完右子树的结果赋给 root->right,最后返回 root 节点

代码实现

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        if(root == nullptr) return nullptr;
        if(root->val < low){
            TreeNode* right = trimBST(root->right, low, high);
            return right;
        }
        if(root->val > high){
            TreeNode* left = trimBST(root->left, low, high);
            return left;
        }
        root->left = trimBST(root->left, low, high);
        root->right = trimBST(root->right, low, high);
        return root;
    }
};

精简后:

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        if (root == nullptr) return nullptr;
        if (root->val < low) return trimBST(root->right, low, high);
        if (root->val > high) return trimBST(root->left, low, high);
        root->left = trimBST(root->left, low, high);
        root->right = trimBST(root->right, low, high);
        return root;
    }
};

108.将有序数组转换为二叉搜索树

题目

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。

示例 1:

输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:

在这里插入图片描述
在这里插入图片描述

提示:

  • 1 <= nums.length <= 10(4)

  • -10(4) <= nums[i] <= 10(4)

  • nums严格递增 顺序排列

思路

递归三部曲

  • 确定递归函数返回值以及参数

    • 用递归函数的返回值来构造中节点的左右孩子
    • 参数,传入数组的左下标 left 和右下标 right
  • 确定递归终止条件

    • 区间定义左闭右闭,当区间 left > right,是空节点
  • 确定单层递归逻辑

    • 取数组中间元素int mid = left + ((right - left) / 2);// 这么写不会越界
    • 以中间位置的元素构造节点TreeNode* root = new TreeNode(nums[mid]);,如果是偶数长度的数组,取靠左边的
    • 划分区间,root 的左孩子接住下一层左区间的构造节点,右孩子同理
    • 最后返回 root

注意:在调用traversal的时候为什么传入的left和right为什么是0和nums.size() - 1,因为定义的区间为左闭右闭。

代码实现

class Solution {
private:
    TreeNode* traversal(vector<int>& nums, int left, int right){
        if(left > right) return NULL;
        int mid = left + ((right - left) / 2);// 这么写不会越界
        TreeNode* root = new TreeNode(nums[mid]);
        root->left = traversal(nums, left, mid - 1);
        root->right = traversal(nums, mid + 1, right);
        return root;
    }
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return traversal(nums, 0, nums.size() -1);
    }
};

538.把二叉搜索树转换为累加树

题目

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

  • 节点的左子树仅包含键 小于 节点键的节点。

  • 节点的右子树仅包含键 大于 节点键的节点。

  • 左右子树也必须是二叉搜索树。

示例 1:

输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]

在这里插入图片描述

提示:

  • 树中的节点数介于 010(4)( )之间。

  • 每个节点的值介于 -10(4)10(4) 之间。

  • 树中的所有值 互不相同

  • 给定的树为二叉搜索树。

思路

其实就是从最后一个叶子节点开始,不断往前累加,所以反中序遍历就可以了

在这里插入图片描述

递归函数三部曲:

  • 递归函数参数以及返回值

    • 不需要返回值,要遍历整棵树
    • 参数需要定义一个全局变量 pre,用来保存 cur 节点的前一个节点的数值,定义为 int 型
  • 确定终止条件

    • 遇空就终止
  • 确定单层递归逻辑

    • 用右中左来遍历二叉树,中节点的处理逻辑就是让 cur 的数值加上前一个节点的数值

代码实现

class Solution {
private:
    int pre = 0;
    void traversal(TreeNode* cur){
        if(cur == NULL) return;
        traversal(cur->right);
        cur->val += pre;
        pre = cur->val;
        traversal(cur->left);
    }
public:
    TreeNode* convertBST(TreeNode* root) {
        int pre = 0;
        traversal(root);
        return root;
    }
};

二叉树总结

复习链接:

https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E6%80%BB%E7%BB%93%E7%AF%87.html#%E9%98%B6%E6%AE%B5%E6%80%BB%E7%BB%93

遍历顺序:

  • 涉及到二叉树的构造,如论普通还是二叉搜索树,一定前序,都是先构造中节点

  • 求普通二叉树的属性,一般是后序,一般要通过递归函数的返回值做计算

    • 如果单纯求深度就用前序
  • 求二叉搜索树的属性,一定是中序,合理利用有序性

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值