0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何修剪二叉搜索树

算法与数据结构 来源:代码随想录 作者:程序员Carl 2021-10-11 14:16 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

如果不对递归有深刻的理解,本题有点难。单纯移除一个节点那还不够,要修剪!

669. 修剪二叉搜索树

给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。

思路

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

但还真的不简单!

递归法

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

不难写出如下代码:

classSolution{
public:
TreeNode*trimBST(TreeNode*root,intlow,inthigh){
if(root==nullptr||root->val< low || root->val>high)returnnullptr;
root->left=trimBST(root->left,low,high);
root->right=trimBST(root->right,low,high);
returnroot;
}
};

然而[1, 3]区间在二叉搜索树的中可不是单纯的节点3和左孩子节点0就决定的,还要考虑节点0的右子树

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

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

其实不用重构那么复杂。

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

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

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

这里我们为什么需要返回值呢?

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

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

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

代码如下:

TreeNode*trimBST(TreeNode*root,intlow,inthigh)
  • 确定终止条件

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

if(root==nullptr)returnnullptr;
  • 确定单层递归的逻辑

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

代码如下:

if(root->val< low) {
    TreeNode* right = trimBST(root->right,low,high);//寻找符合区间[low,high]的节点
returnright;
}

如果root(当前节点)的元素大于high的,那么应该递归左子树,并返回左子树符合条件的头结点。

代码如下:

if(root->val>high){
TreeNode*left=trimBST(root->left,low,high);//寻找符合区间[low,high]的节点
returnleft;
}

接下来要将下一层处理完左子树的结果赋给root->left,处理完右子树的结果赋给root->right。

最后返回root节点,代码如下:

root->left=trimBST(root->left,low,high);//root->left接入符合条件的左孩子
root->right=trimBST(root->right,low,high);//root->right接入符合条件的右孩子
returnroot;

此时大家是不是还没发现这多余的节点究竟是如何从二叉树中移除的呢?

在回顾一下上面的代码,针对下图中二叉树的情况:

如下代码相当于把节点0的右孩子(节点2)返回给上一层,

if(root->val< low) {
    TreeNode* right = trimBST(root->right,low,high);//寻找符合区间[low,high]的节点
returnright;
}

然后如下代码相当于用节点3的左孩子 把下一层返回的 节点0的右孩子(节点2) 接住。

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

此时节点3的右孩子就变成了节点2,将节点0从二叉树中移除了。

最后整体代码如下:

classSolution{
public:
TreeNode*trimBST(TreeNode*root,intlow,inthigh){
if(root==nullptr)returnnullptr;
if(root->val< low) {
            TreeNode* right = trimBST(root->right,low,high);//寻找符合区间[low,high]的节点
returnright;
}
if(root->val>high){
TreeNode*left=trimBST(root->left,low,high);//寻找符合区间[low,high]的节点
returnleft;
}
root->left=trimBST(root->left,low,high);//root->left接入符合条件的左孩子
root->right=trimBST(root->right,low,high);//root->right接入符合条件的右孩子
returnroot;
}
};

精简之后代码如下:

classSolution{
public:
TreeNode*trimBST(TreeNode*root,intlow,inthigh){
if(root==nullptr)returnnullptr;
if(root->val< low) returntrimBST(root->right,low,high);
if(root->val>high)returntrimBST(root->left,low,high);
root->left=trimBST(root->left,low,high);
root->right=trimBST(root->right,low,high);
returnroot;
}
};

只看代码,其实不太好理解节点是符合移除的,这一块大家可以自己在模拟模拟!

迭代法

因为二叉搜索树的有序性,不需要使用栈模拟递归的过程。

在剪枝的时候,可以分为三步:

  • 将root移动到[L, R] 范围内,注意是左闭右闭区间
  • 剪枝左子树
  • 剪枝右子树

代码如下:

classSolution{
public:
TreeNode*trimBST(TreeNode*root,intL,intR){
if(!root)returnnullptr;

//处理头结点,让root移动到[L,R]范围内,注意是左闭右闭
while(root!=nullptr&&(root->val< L || root->val>R)){
if(root->val< L) root = root->right;//小于L往右走
elseroot=root->left;//大于R往左走
}
TreeNode*cur=root;
//此时root已经在[L,R]范围内,处理左孩子元素小于L的情况
while(cur!=nullptr){
while(cur->left&&cur->left->val< L) {
                cur->left=cur->left->right;
}
cur=cur->left;
}
cur=root;

//此时root已经在[L,R]范围内,处理右孩子大于R的情况
while(cur!=nullptr){
while(cur->right&&cur->right->val>R){
cur->right=cur->right->left;
}
cur=cur->right;
}
returnroot;
}
};

总结

修剪二叉搜索树其实并不难,但在递归法中大家可看出我费了很大的功夫来讲解如何删除节点的,这个思路其实是比较绕的。

最终的代码倒是很简洁。

如果不对递归有深刻的理解,这道题目还是有难度的!

本题我依然给出递归法和迭代法,初学者掌握递归就可以了,如果想进一步学习,就把迭代法也写一写。

其他语言版本

Java

classSolution{
publicTreeNodetrimBST(TreeNoderoot,intlow,inthigh){
if(root==null){
returnnull;
}
if(root.val< low) {
            returntrimBST(root.right,low,high);
}
if(root.val>high){
returntrimBST(root.left,low,high);
}
//root在[low,high]范围内
root.left=trimBST(root.left,low,high);
root.right=trimBST(root.right,low,high);
returnroot;
}
}

Python

classSolution:
deftrimBST(self,root:TreeNode,low:int,high:int)->TreeNode:
ifnotroot:returnroot
ifroot.val< low:
            returnself.trimBST(root.right,low,high)//寻找符合区间[low,high]的节点
ifroot.val>high:
returnself.trimBST(root.left,low,high)//寻找符合区间[low,high]的节点
root.left=self.trimBST(root.left,low,high)//root->left接入符合条件的左孩子
root.right=self.trimBST(root.right,low,high)//root->right接入符合条件的右孩子
returnroot
责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 源代码
    +关注

    关注

    96

    文章

    2953

    浏览量

    70858
  • 二叉树
    +关注

    关注

    0

    文章

    74

    浏览量

    13024

原文标题:修剪一棵二叉搜索树

文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    UniStore正式全面开放

    5月7日,宇科技正式宣布,全球首个人形机器人任务动作应用商店——宇UniStore官方共享应用平台即日起面向全球用户全面开放。用户可通过该平台开发和下载机器人应用,像安装手机App一样简单,无需任何底层编程能力。
    的头像 发表于 05-09 11:22 1085次阅读

    科技,IPO申请获受理

    电子发烧友网综合报道 3月20日,上交所网站显示,宇科技股份有限公司科创板IPO申请已受理,成为又一家科创板IPO“预先审阅”落地项目。此次IPO,宇科技拟募资42.02亿元。   招股书显示
    的头像 发表于 03-20 18:33 4400次阅读
    宇<b class='flag-5'>树</b>科技,IPO申请获受理

    1688按图搜索API技术实现详解

    API允许开发者通过上传商品图片,检索1688平台上与之相似的商品列表。其核心功能是图像识别与商品匹配。 、 准备工作 获取API权限 访问1688开放平台注册开发者账号。 创建应用,获取 App Key 和 App Secret。 在应用权限中申请 按图搜索商品 接口
    的头像 发表于 03-13 17:01 947次阅读
    1688按图<b class='flag-5'>搜索</b>API技术实现详解

    ​​​​​​​使用 DMM Web API 获取搜索列表数据

    ​  DMM 平台提供了丰富的 Web API 接口,允许开发者获取其平台上的各种数据。其中一个常用的接口是用于获取搜索列表结果的 API。本文将介绍如何调用此 API 来获取商品或内容的列表信息
    的头像 发表于 02-09 15:34 459次阅读
    ​​​​​​​使用 DMM Web API 获取<b class='flag-5'>搜索</b>列表数据

    TÜV莱茵与杭集团达成战略合作并颁发欧盟CE-MD符合性证书

    日前,国际独立第三方检测、检验和认证机构德国莱茵TÜV大中华区(简称"TÜV莱茵")与杭集团股份有限公司(简称"杭集团")签署了战略合作协议,标志着双方
    的头像 发表于 01-15 12:18 520次阅读

    亿纬锂能与杭集团达成战略合作

    近日,亿纬锂能与杭集团2025年战略研讨会暨战略合作协议签约仪式在杭州举行。亿纬锂能副总裁、商用车电池产品线总裁江吉兵博士,亿纬锂能商用车电池产品线国内销售部总经理井振江,杭集团董事、副总经理兼
    的头像 发表于 01-04 18:18 1230次阅读

    淘宝图片搜索商品API指南

    一、摘要 淘宝图片搜索商品API是基于图像识别技术的智能搜索接口,允许用户通过上传商品图片来搜索相似或同款商品。该接口广泛应用于比价、找同款、商品识别等电商场景。 、接口概述 1.功
    的头像 发表于 12-08 14:26 1424次阅读

    线性搜索搜索介绍

    线性搜索(Linear Search):从数组的第一个元素开始,依次将当前元素与目标值进行比较,直到找到目标值或搜索完整个数组。 搜索(Binary Search):在有序数组中查
    发表于 12-01 07:36

    item_search-按关键字搜索商品列表API接口

    用户提供更好的购物体验。 、关键词搜索API接口概述 淘宝关键词搜索API接口是一个HTTP接口,支持GET请求。开发者可以通过该接口在淘宝上搜索商品,并获取相关商品的信息。该接口提
    的头像 发表于 11-16 17:13 473次阅读

    通过优化代码来提高MCU运行效率

    选择时间复杂度低的算法。 根据访问模式选择数据结构。频繁查找用哈希表,有序数据用二叉树等。 查表法:对于复杂的数学计算(如sin, log),或者协议解析,预先计算好结果存于数组中,用空间换时间
    发表于 11-12 08:21

    按图搜索1688商品的API接口

    ​  在电商场景中,按图搜索商品功能(即通过上传图片查找相似商品)极大提升了用户体验和效率。1688作为阿里巴巴旗下的批发平台,虽然没有直接公开的“按图搜索”API,但我们可以借助阿里云的图像搜索
    的头像 发表于 10-22 15:05 991次阅读
    按图<b class='flag-5'>搜索</b>1688商品的API接口

    请问rtt studio 的文件夹打红什么意思?

    rtt studio 的文件夹打红什么意思?而且文件夹里面实际是有文件的,但是浏览不出来。
    发表于 09-18 06:34

    产品搜索与过滤API接口

    ​ 在现代化电子商务和应用程序开发中,高效的产品搜索与过滤功能至关重要。它能帮助用户快速找到所需商品,提升用户体验和转化率。产品搜索与过滤API接口作为后端服务的核心组件,允许开发者通过编程方式实现
    的头像 发表于 07-24 14:35 740次阅读
    产品<b class='flag-5'>搜索</b>与过滤API接口

    AI搜索一夜变天,专为Agent做搜索的赛道能否诞生百亿美金新巨头?

    ChatGPT刚刚给火热的Agent市场添把柴,这边AI搜索市场却要变天。 Bing Search API将于8月11日关停,所有Bing Search API都将 完全停用 ,同时不再接受新用户
    的头像 发表于 07-24 13:59 848次阅读
    AI<b class='flag-5'>搜索</b>一夜变天,专为Agent做<b class='flag-5'>搜索</b>的赛道能否诞生百亿美金新巨头?

    亿纬锂能荣获杭集团2022-2024年度优秀供应商奖

    近日,亿纬锂能凭借卓越产品、可靠交付与优质服务荣获杭集团颁发的“2022-2024年度优秀供应商”奖。杭集团副总经理兼杭电器董事长金华曙、杭电器总经理兼杭博电机总经理李明辉出席
    的头像 发表于 07-15 09:00 1158次阅读