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

本文介绍了如何通过递归方法修剪二叉搜索树以保持元素在指定范围,以及如何将有序数组转换为平衡二叉搜索树和把二叉搜索树转换为累加树。每种操作涉及的解题思路、代码实现和复杂度分析都被详细讨论。
摘要由CSDN通过智能技术生成

修剪二叉搜索树

链接: 修剪二叉搜索树

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

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

思路

递归处理

解题方法

  • 确定递归函数的参数以及返回值
    要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是从二叉树中移除节点)的操作。
    有返回值,更方便,可以通过递归函数的返回值来移除节点

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

  • 确定单层递归的逻辑
    如果root(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树符合条件的头结点。

复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

Code

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

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

链接: 将有序数组转换为二叉搜索树

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

思路

这题最重要的是中序遍历
这样就有三种写法:
总是选择中间位置左边的数字作为根节点
总是选择中间位置右边的数字作为根节点
选择任意一个中间位置数字作为根节点

解题方法

我们使用方法一(左边结点为根节点)

复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(logn)

Code

class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return helper(nums, 0, nums.size() - 1);
    }

    TreeNode* helper(vector<int>& nums, int left, int right) {
        if (left > right) {
            return nullptr;
        }

        // 总是选择中间位置左边的数字作为根节点
        int mid = (left + right) / 2;

        TreeNode* root = new TreeNode(nums[mid]);
        root->left = helper(nums, left, mid - 1);
        root->right = helper(nums, mid + 1, right);
        return root;
    }
};

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

链接: 把二叉搜索树转换为累加树

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

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

节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。

思路

这就是一个有序数组[2, 5, 13],求从后到前的累加数组,也就是[20, 18, 13]

解题方法

从树中可以看出累加的顺序是右中左,所以我们需要反中序遍历这个二叉树,然后顺序累加就可以了
本题需要一个pre指针记录当前遍历节点cur的前一个节点,这样才方便做累加

复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

Code

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) {
        pre = 0;
        traversal(root);
        return root;
    }
};

总结

  • 第一道题目比较难,比添加增加和删除节点难的多

  • 第二题就简单一些

  • 第三题也不难,在 求二叉搜索树的最小绝对差 和 众数 那两道题目 都讲过了 双指针法,思路是一样的。

  • 二叉树过完了,感觉还是不怎么懂,有些题想了很久都想不出来,得看视频的题解才行,迭代法都没怎么看

  • 过几天把day20写了,对二叉树做一个总结

  • 参考文档

  • 链接: 修剪二叉搜索树

  • 链接: 将有序数组转换为二叉搜索树

  • 链接: 把二叉搜索树转换为累加树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值