代码随想录算法训练营第60期第二十一天打卡

大家好,今天应该是二叉树的最后一个板块了,其实纵观整个二叉树章节,我们发现递归是非常常用的方法,因为其实所有的子树都具有一样的处理方法,这样自己调用自己就会有递归,那还有一些操作比如最近公共祖先与节点的插入与删除操作,求深度与高度操作,这些其实大部分都是递归可以实现的,还有我们比较特殊的二叉搜索树,那么我们就进入我们二叉树的最后一个板块。我们要为二叉树画上一个圆满的句号。

第一题对应力扣编号为669的题目修剪二叉搜索树

我们来看一下题目,题目到底要求我们如何修剪?

这个看上去还是有难度的,我们要删除不在范围内的节点,那这估计又会涉及到二叉树的结构调整,我们来看一下究竟应该如何解决?其实有些朋友可能会感觉很简单啊?我直接看根节点的值如果根节点是空节点或者根节点的值小于low大于high这样直接返回空,然后递归左右子树就可以,其实这个方法是不可以的,想简单了,其实本题似乎也不需要涉及重构了,这个给大家举个例子就可以明白,

这个例子的修剪区间在[1,3],那我们可以发现0不在区间内应该删除,但是删除了以后大家其实可以看到我直接把节点0的右子树接在节点3的左子树就可以了,其实没有涉及到重构,那我们理解了本题的关键部分,接下来重要的就是递归的单层逻辑如何写?首先确定终止条件就是root为空的话就返回空,如果root(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树符合条件的头结点。如果root(当前节点)的元素大于high的,那么应该递归左子树,并返回左子树符合条件的头结点。这个一定要注意我们的递归方向,最后可以得到我们的递归代码:

cpp 复制代码
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); // 寻找符合区间[low, high]的节点
            return right;
        }
        if (root->val > high) {
            TreeNode* left = trimBST(root->left, low, high); // 寻找符合区间[low, high]的节点
            return left;
        }
        root->left = trimBST(root->left, low, high); // root->left接入符合条件的左孩子
        root->right = trimBST(root->right, low, high); // root->right接入符合条件的右孩子
        return root;
    }
};

关于这道题目我还想告诉大家的是,多去观察,我起初是以为要再去改变二叉树的结构的,因为我毕竟会删除不在范围内的节点,其实不需要,我们可以考虑只要没有被删除的一定是符合题目的范围的,而且这又是一棵二叉搜索树本就有特殊的性质,因此只要我根节点大了或者小了一定可以在其左子树或者右子树找到符合要求的根节点。

第二题对应力扣编号为108的题目将有序数组转换为二叉搜索树

我拿到这道题目的时候这道题应该是很简单的,二叉搜索树的中序遍历就是从小到大排序的,而题目恰巧给我们了一个升序的数组:

那我们一起来分析一下如何根据这个有序数组来构建我们的二叉搜索树,但是题目强调了要是平衡的,如果没有平衡这个条件的话其实所有的数组都可以转化成线性的二叉搜索树,以第一个元素为根节点依次往右边排列不就是一棵二叉搜索树,但是题目要求平衡就是左右子树都要存在,这就有点意思了,大家可以思考一下我们是不是取数组的中间位置的元素作为二叉树的根节点,前面的元素都是左子树,后面的都是右子树,大家也可以看一下其实这棵二叉搜索树不见得是唯一的:

这个就受到了节点值大小的影响,都是符合题目要求的,其实递归的思路就不算很难了,但是大家要注意一点就是根节点的问题,我们这里稍微用一点二分去找中间元素,这样才可以确定根节点,剩下的就是找到左子树的元素与右子树的元素即可:

cpp 复制代码
class Solution {
private:
    TreeNode* traversal(vector<int> &nums, int left, int right)
    {
        if (left > right) return NULL;
        int mid = (right + left) >> 1;
        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) {
        TreeNode *root = traversal(nums, 0, nums.size() - 1);
        return root;
    }
};

这道题目其实难度不算太大,只要大家对二叉搜索树的性质掌握的清楚,对递归理解的透彻其实这道题还是可以写出来的。

第三题对应力扣编号为538的把二叉树搜索树转换为累加树

这是我们今天的最后一道题,也是我们二叉树章节的最后一道题,我们就一起来看一下最后这一道题:

我强制帮大家把示例截下来了,这样大家看着方便一些,看完题目我大致明白了就是我们把这棵二叉搜索树每一个节点转换为这棵树中大于等于他的节点的和,其实大家是不是也可以知道我们最新形成的这棵树它本身不会是搜索二叉树了,但是它的左右子树还是二叉搜索树,这个大家要注意,其实大家想想也就明白了,二叉搜索树的话左边的值小,比它大的肯定多这些比他大的加起来那肯定就大,右边的值大,其实比它小的就少,加起来也就小了,大家应该理解了这有点数学思想,其实我告诉大家一句就是如果想成为一名优秀的程序员或者是算法工程师数学也很重要的,那接下来我们就可以着手写代码了,写代码之前我们先来看一下我上面的那棵树,8的话就是8,7的话是不是7+8,6的话是不是6+7+8,这样大家是否发现规律了,其实是不是就是倒序求累加和呀,其实大家或许感觉在数组里倒序求累加和挺简单的,我们直接就会想到双指针的操作,一个cur一个pre就可以,每加完一个数我的两个指针就同步往前移即可,其实在二叉搜索树里也是一样的,但注意由于我们是倒序的因此这里我们就要选用右根左了,代码如下:

cpp 复制代码
class Solution {
private:
    int pre = 0;
    //为啥设置成整形而不是TreeNode*呢?考虑到空指针引发异常
    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;
    }
};

大家注意最后我如何调用的递归函数,我是从根节点开始的,最后返回根节点就可以了,这一路递归下来就可以实现累加树。

总结

到目前为止,我们不仅仅是今天的题目讲完了,二叉树章节也讲完了,回顾前面的数组,链表,哈希表,字符串,栈与队列,大家不知道还记得多少,大家要记得及时复习,二叉树我们主要使用了递归与迭代两种遍历方法,尤其是递归使用尤为广泛,二叉搜索树我们的题目也在一直涉及,大家要引起重视,好今天的分享就到这里,下一次我们就将进入回溯算法章节。

相关推荐
渭雨轻尘_学习计算机ing19 分钟前
二叉树构建算法全解析
算法·程序员
乌鸦94442 分钟前
《数据结构之美--二叉树》
数据结构·#二叉树
C语言魔术师2 小时前
70. 爬楼梯
算法·动态规划
跳跳糖炒酸奶2 小时前
第二章、Isaaclab强化学习包装器(1)
人工智能·python·算法·ubuntu·机器人
许_安2 小时前
leetcode刷题日记——两数相加
算法·leetcode·职场和发展
夜晚中的人海2 小时前
【C语言】初阶算法相关习题(二)
c语言·开发语言·算法
PXM的算法星球3 小时前
【算法笔记】贪心算法
笔记·算法·贪心算法
傻欣3 小时前
代码随想录学习笔记---二叉树
笔记·学习·算法
WW_千谷山4_sch3 小时前
MYOJ_1349:(洛谷P3951)[NOIP 2017 提高组] 小凯的疑惑(数学公式套用,两步搞定代码)
c++·算法
我想进大厂3 小时前
图论---拓扑排序(DFS)
算法·深度优先·图论