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

本文解析了LeetCode中的三个问题:修剪二叉搜索树(通过区间裁剪简化结构),有序数组转换为二叉搜索树(利用中值确定节点),以及二叉搜索树转换为累加树(后序遍历求节点累加值)。作者强调了递归思想和巧妙的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、LeetCode 669. 修剪二叉搜索树

状态:已解决

1.思路 

        这道题确实蛮难想的,以为是跟删除节点的五个分支差不多,没想到比删除节点操作很简单,就是思路更巧妙。

        由于是一棵二叉搜索树,因此树中落在区间[low,high]中的节点实际横跨了一定长度。

        那么对于在区间外的节点:

        (1)如果node->val < low,则该节点的左子树各节点值也一定小于low,因此可以采取让该节点的父节点直接连该节点的右子树。注:一定也是经相同递归操作后被返回的右子树节点值,而不是原始的右子树节点值,因为右子树中某节点的左子树也可能小于low。如low=2,high=3时,上图0的右孩子节点为2,但2的左孩子为1,依旧小于low。

        (2)如果node->val > high,则该节点的右子树各节点值也一定大于high,因此可以采取让该节点的父节点直接连该节点的左子树(注:一定也是经相同递归操作后被返回的右子树节点值,而不是原始的右子树节点值,因为左子树中某节点的右子树也可能大于high)。

想明白后就可以使用递归三部曲了:

(1)返回值和参数:返回值当然是TreeNode*,因为每层递归需要给上层递归返回处理后的左右子树。参数依旧是:每层递归的节点root,区间左值low,区间右值high。 

TreeNode* trimBST(TreeNode* root, int low, int high)

(2)终止条件:遇到空节点、遇到落在区间外的节点

if(root == NULL) return NULL;
if(root->val < low){
    return trimBST(root->right,low,high);
}
if(root->val > high){
    return trimBST(root->left,low,high);
}

(3)每层递归逻辑:遍历左右子树,得到修改后的左右孩子,该节点已修改完毕,再往上返回。

root->left = trimBST(root->left,low,high);
root->right = trimBST(root->right,low,high);
return root;

2.完整代码

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        if(root == NULL) return NULL;
        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.将有序数组转换为二叉搜索树

状态:已解决

1.思路

        这道题的本质就是根据数组构造一棵二叉树。根据之前所学的知识,如果要构造二叉树,就必须要确定中间结点,然后分布构造左子树和右子树。对于106.从中序与后序遍历序列构造二叉树来说,中间结点是根据后序遍历来确定的,左区间和右区间则是中间结点去切割中序遍历序列得到的两个子区间。而此题更简单,因为中间结点直接就是序列的中间值,左右区间就是根据中间值为切割线的两个子区间(二叉搜索树的有序特性)。

        为什么这种做法得到的结果一定就是平衡二叉树呢?因为每次根据中间值切割得到的左右区间长度要么相等,要么差1,刚好满足平衡二叉树的定义,故此方法可行。

2.代码实现

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

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

状态:已解决

1.思路 

        这道题自己想出来了,卡哥总结的公式真的很好用!二叉树的大部分题看着要求五花八门,本质上无非是对递归三种遍历方式的各种应用。

这是一棵二叉搜索树,题目要求“使每个节点 node 的新值 等于 原树中大于或等于 node.val 的值之和。” 实则,就是让你后序遍历做节点值的累加和。由于要累加,需要知道遍历顺序下,前一个节点的累加和(该节点的累加值=该节点的原始值+前一个节点的累加值)。然而,针对后序遍历,我们在遍历中间结点时,都知道上一个节点是中间结点的右孩子,即root->right,但是在遍历左孩子时,我们确实清楚左孩子的上一个节点是它的父亲,但是我们无法表示出一个节点的父亲,因此,需用双指针法来指向上一个节点。

明确了思路,根据递归三部曲,可以直接写出代码。 

2.代码实现

class Solution {
public:
    TreeNode* pre = NULL;
    void traversal(TreeNode* cur){
        if(cur == NULL) return ;
        traversal(cur->right);//右

        //中,做节点处理工作
        if(pre){
            cur->val = cur->val + pre->val;
        }
        pre = cur; 

        //左
        traversal(cur->left);
    }
    TreeNode* convertBST(TreeNode* root) {
        traversal(root);
        return root;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值