代码随想录【Day 23】 | 669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树

题目链接:669. 修剪二叉搜索树

卡尔文解

视频讲解

解题思路及注意事项:

相信看到这道题目大家都感觉是一道简单题(事实上leetcode上也标明是简单)。

但还真的不简单!

递归法

直接想法就是:递归处理,然后遇到 root->val < low || root->val > high 的时候直接return NULL,一波修改,赶紧利落。

不难写出如下代码:
在这里插入图片描述
然而[1, 3]区间在二叉搜索树的中可不是单纯的节点3和左孩子节点0就决定的,还要考虑节点0的右子树

我们在重新关注一下第二个示例,如图:

在这里插入图片描述

所以以上的代码是不可行的!

从图中可以看出需要重构二叉树,想想是不是本题就有点复杂了。

其实不用重构那么复杂。

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

在这里插入图片描述

理解了最关键部分了我们再递归三部曲:

确定递归函数的参数以及返回值
这里我们为什么需要返回值呢?

因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是从二叉树中移除节点)的操作。

但是有返回值,更方便,可以通过递归函数的返回值来移除节点。

这样的做法在二叉树:搜索树中的插入操作 (opens new window)和二叉树:搜索树中的删除操作 (opens new window)中大家已经了解过了。

代码实现:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {

        if( !root ) return NULL;

        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;

    }
};

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

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

卡尔文解

视频讲解

解题思路及注意事项:

在二叉树:构造二叉树登场! (opens new window)和二叉树:构造一棵最大的二叉树 (opens new window)中其实已经讲过了,如果根据数组构造一棵二叉树。

本质就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间。

本题其实要比二叉树:构造二叉树登场! (opens new window)和 二叉树:构造一棵最大的二叉树 (opens new window)简单一些,因为有序数组构造二叉搜索树,寻找分割点就比较容易了。

分割点就是数组中间位置的节点。

那么为问题来了,如果数组长度为偶数,中间节点有两个,取哪一个?

取哪一个都可以,只不过构成了不同的平衡二叉搜索树。

例如:输入:[-10,-3,0,5,9]

如下两棵树,都是这个数组的平衡二叉搜索树:

在这里插入图片描述

如果要分割的数组长度为偶数的时候,中间元素为两个,是取左边元素 就是树1,取右边元素就是树2。

这也是题目中强调答案不是唯一的原因。 理解这一点,这道题目算是理解到位了。

代码实现:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {

    // 区间: 左闭 右闭 [ ]
    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.把二叉搜索树转换为累加树

题目链接:538.把二叉搜索树转换为累加树

卡尔文解

视频讲解

解题思路及注意事项:

一看到累加树,相信很多小伙伴都会疑惑:如何累加?遇到一个节点,然后再遍历其他节点累加?怎么一想这么麻烦呢。

然后再发现这是一棵二叉搜索树,二叉搜索树啊,这是有序的啊。

那么有序的元素如何求累加呢?

其实这就是一棵树,大家可能看起来有点别扭,换一个角度来看,这就是一个有序数组[2, 5, 13],求从后到前的累加数组,也就是[20, 18, 13],是不是感觉这就简单了。

为什么变成数组就是感觉简单了呢?

因为数组大家都知道怎么遍历啊,从后向前,挨个累加就完事了,这换成了二叉搜索树,看起来就别扭了一些是不是。

那么知道如何遍历这个二叉树,也就迎刃而解了,从树中可以看出累加的顺序是右中左,所以我们需要反中序遍历这个二叉树,然后顺序累加就可以了。

#递归
遍历顺序如图所示:

在这里插入图片描述

本题依然需要一个pre指针记录当前遍历节点cur的前一个节点,这样才方便做累加。

pre指针的使用技巧,我们在二叉树:搜索树的最小绝对差 (opens new window)和二叉树:我的众数是多少? (opens new window)都提到了,这是常用的操作手段。

代码实现:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {

private:
    int prev = 0;

    void traversal( TreeNode *node ){

        if( !node ) return;

        traversal( node->right );

        node->val += prev;
        prev = node->val;

        traversal( node->left );
    }

public:
    TreeNode* convertBST(TreeNode* root) {

        traversal( root );
        return root;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值