当前位置: 首页 > news >正文

LeetCode450. 删除二叉搜索树中的节点

450. 删除二叉搜索树中的节点

文章目录

      • [450. 删除二叉搜索树中的节点](https://leetcode.cn/problems/delete-node-in-a-bst/)
        • 一、题目
        • 二、题解
          • 方法一:递归(一种麻烦的方法)
          • 方法二:优化后的递归


一、题目

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

一般来说,删除节点可分为两个步骤:

  1. 首先找到需要删除的节点;
  2. 如果找到了,删除它。

示例 1:

img

输入:root = [5,3,6,2,4,null,7], key = 3
输出:[5,4,6,2,null,null,7]
解释:给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。
一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。
另一个正确答案是 [5,2,6,null,4,null,7]。

示例 2:

输入: root = [5,3,6,2,4,null,7], key = 0
输出: [5,3,6,2,4,null,7]
解释: 二叉树不包含值为 0 的节点

示例 3:

输入: root = [], key = 0
输出: []

提示:

  • 节点数的范围 [0, 104].
  • -105 <= Node.val <= 105
  • 节点值唯一
  • root 是合法的二叉搜索树
  • -105 <= key <= 105

进阶: 要求算法时间复杂度为 O(h),h 为树的高度。

二、题解

方法一:递归(一种麻烦的方法)

主要思路如下:

  1. findNode 函数:这个函数用于在给定的二叉搜索树中找到值等于 target 的节点。函数采用递归的方式,在树中搜索目标节点。如果当前节点为空,说明未找到目标节点,返回 nullptr。如果当前节点的值等于目标值,返回该节点。如果当前节点的值大于目标值,说明目标节点在左子树中,递归地搜索左子树。否则,目标节点在右子树中,递归地搜索右子树。

  2. deleteNode 函数:这个函数用于删除二叉搜索树中值为 key 的节点。首先,通过调用 findNode 函数找到待删除的节点 node,同时维护一个指向 node 的父节点 pre。然后根据删除情况进行不同的处理:

    • 如果 pre 为空,说明待删除节点是根节点。然后根据左右子树的情况进行调整,保留右子树并将左子树插入右子树中的最左叶子节点。
    • 如果 pre 非空,根据 pre 的位置判断 node 是其父节点的左子节点还是右子节点。然后根据左右子树的情况进行调整,同样保留右子树并将左子树插入右子树中的最左叶子节点。

最后,删除 node 节点并返回调整后的树。

/*** 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 *pre = nullptr;TreeNode* findNode(TreeNode *root, int target){if(root == nullptr){return root;}if(root->val == target){return root;}pre = root;if(root->val > target){TreeNode *left = findNode(root->left, target);return left;}else{TreeNode *right = findNode(root->right, target);return right;}}TreeNode* deleteNode(TreeNode* root, int key) {TreeNode *node = findNode(root, key);if(node == nullptr) return root;if(pre == nullptr){if(node->left && node->right){TreeNode *temp = node->right;while(temp->left){temp = temp->left;}temp->left = node->left;return node->right;}else if(node->left){return node->left;}else if(node->right){return node->right;}else{return nullptr;}}if(pre && pre -> right == node){if(node->left && node->right){TreeNode *temp = node->right;while(temp->left){temp = temp->left;}temp->left = node->left;pre->right = node->right;}else if(node->left){pre->right = node->left;}else if(node->right){pre->right = node->right;}else{pre->right = nullptr;}}if(pre && pre->left == node){if(node->left && node->right){TreeNode *temp = node->right;while(temp->left){temp = temp->left;}temp->left = node->left;pre->left = node->right;}else if(node->left){pre->left = node->left;}else if(node->right){pre->left = node->right;}else{pre->left = nullptr;}}delete node;return root;}
};
方法二:优化后的递归

算法思路

  1. 递归搜索节点: 首先,我们从根节点开始递归地搜索目标节点(值为key的节点)。

    • 如果当前节点为空,表示没有找到目标节点,直接返回空指针(nullptr)。
    • 如果当前节点的值大于目标key,说明目标节点在左子树中,递归搜索左子树。
    • 如果当前节点的值小于目标key,说明目标节点在右子树中,递归搜索右子树。
    • 如果当前节点的值等于目标key,说明找到了目标节点,继续下一步。
  2. 处理删除操作: 一旦我们找到了目标节点,有几种情况需要处理:

    • 如果目标节点没有左子树,那么我们可以用其右子树来替代这个节点,然后删除这个节点。
    • 如果目标节点没有右子树,类似地,我们可以用其左子树来替代这个节点,然后删除这个节点。
    • 如果目标节点既有左子树又有右子树,我们可以找到其右子树中最小的节点(即右子树中的最左节点,即后继节点),将该节点的值复制到目标节点上,然后递归地在右子树中删除这个后继节点。
  3. 返回根节点: 最后,无论如何都要返回当前子树的根节点。

具体实现

class Solution {
public:TreeNode* deleteNode(TreeNode* root, int key) {if (!root)return nullptr;if (root->val > key) {root->left = deleteNode(root->left, key); // 递归搜索左子树} else if (root->val < key) {root->right = deleteNode(root->right, key); // 递归搜索右子树} else {if (!root->left) { // 没有左子树,用右子树替代TreeNode* temp = root->right;delete root;return temp;} else if (!root->right) { // 没有右子树,用左子树替代TreeNode* temp = root->left;delete root;return temp;}TreeNode* temp = findMin(root->right); // 找到后继节点root->val = temp->val;root->right = deleteNode(root->right, temp->val); // 在右子树中删除后继节点}return root; // 返回根节点}private:TreeNode* findMin(TreeNode* node) {while (node->left)node = node->left;return node; // 找到最左节点,即后继节点}
};

算法分析

  • 在最坏情况下,我们需要遍历BST的高度h,即时间复杂度为O(h)。
  • 递归深度取决于树的高度,所以空间复杂度也是O(h)。

相关文章:

LeetCode450. 删除二叉搜索树中的节点

450. 删除二叉搜索树中的节点 文章目录 [450. 删除二叉搜索树中的节点](https://leetcode.cn/problems/delete-node-in-a-bst/)一、题目二、题解方法一&#xff1a;递归&#xff08;一种麻烦的方法&#xff09;方法二&#xff1a;优化后的递归 一、题目 给定一个二叉搜索树的根…...

Java动态调试技术原理及实践

文章目录 Java动态调试技术原理及实践引言故事场景一:开发调试动态调试技术简介Java Instrumentation简介动态调试技术实践案例分析场景二:线上问题排查动态调试技术实践案例分析总结Java动态调试技术原理及实践 引言 在日常的软件开发过程中,调试是一个非常重要的环节。当…...

Lua + Redis 实战代码

--[[luarocks install luasocket module socket not foundhttps://github.com/nrk/redis-lua最历害的是&#xff0c;用redis 去跑lua&#xff0c;分布式锁&#xff0c;限流&#xff0c;]]--local redis require("redis");local config{host"127.0.0.1&…...

类的访问限定符,实例化,对象存储方式,this指针

目录 类的定义 类的两种定义方式&#xff1a; 访问限定符 类的实例化 类对象的存储方式 this指针 C语言结构体中只能定义变量&#xff0c;在C中&#xff0c;结构体内不仅可以定义变量&#xff0c;也可以定义函数。比如&#xff1a; 之前在数据结构初阶中&#xff0c;用C语…...

《Linux从练气到飞升》No.15 Linux 环境变量

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的…...

Spring Boot 重启命令

Spring Boot 重启命令 本文描述了一个重启Spring Boot命令执行过程和示例 本文利用kill -9 关闭进程&#xff0c;不优雅&#xff0c;会突然中断程序&#xff0c;可能导致数据和逻辑异常 搜索微信小程序【亚特技术】在资源中搜索【优雅】可得到Spring Boot如何优化重启 1. 过…...

pdf怎么合并在一起?这几个合并方法了解一下

pdf怎么合并在一起&#xff1f;在日常工作、学习和生活中&#xff0c;我们常常会遇到需要将多个PDF文件合并成一个文件的情况。比如&#xff0c;在学术论文写作中&#xff0c;我们可能需要将多篇论文合并成一个文件进行打印和提交。在工作中&#xff0c;我们可能需要将多个报告…...

【仿写tomcat】七、项目结构优化以及代码开源

仿写tomcat 项目结构开源地址 项目结构 到目前为止&#xff0c;博主的仿写tomcat就告一段落了&#xff0c;后续有时间了还会继续补充功能&#xff0c;现在的项目结构如下。 在保证功能的前提下作出的改动有&#xff1a; 将各个类中的参数统一成了Config类&#xff0c;通过对…...

泛微E8配置自定义触发流程失败

在新公司接了个配置泛微流程触发的活。因为泛微的官方文档并没有详细的操作指引&#xff0c;在测试环境配置之后、要触发的流程可以手工提交&#xff0c;但是触发一直不成功。简单记录下业务场景和其他处理信息&#xff0c;以供参考。 应用版本 目前使用了泛微 E8 &#xff0…...

Springboot整合Mybatis调用Oracle存储过程

1、配置说明 Oracel11g+springboot2.7.14+mybatis3.5.13 目标:springboot整合mybatis访问oracle中的存储过程,存储过程返回游标信息。 mybatis调用oracle中的存储过程方式 2、工程结构 3、具体实现 3.1、在Oracle中创建测试数据库表 具体数据可自行添加 create table s…...

【java安全】Log4j反序列化漏洞

文章目录 【java安全】Log4j反序列化漏洞关于Apache Log4j漏洞成因CVE-2017-5645漏洞版本复现环境漏洞复现漏洞分析 CVE-2019-17571漏洞版本漏洞复现漏洞分析 参考 【java安全】Log4j反序列化漏洞 关于Apache Log4j Log4j是Apache的开源项目&#xff0c;可以实现对System.out…...

[mars3d 打包]vue3+vite,打包后mars3d找不到

前提 &#xff1a; vue3vite开发框架&#xff1b;使用 官网 方式3获取sdk,引入mars3d; 问题&#xff1a;开发时一切正常&#xff0c;打包之后&#xff0c;页面白屏&#xff0c;没有渲染&#xff1b; 相关的mars3d的相关方法会报错&#xff1b;但是mars3d的打印日志是有的&…...

STM32——SPI外设总线

SPI外设简介 STM32内部集成了硬件SPI收发电路&#xff0c;可以由硬件自动执行时钟生成、数据收发等功能&#xff0c;减轻CPU的负担 可配置8位/16位数据帧、高位先行/低位先行 时钟频率&#xff1a; fPCLK / (2, 4, 8, 16, 32, 64, 128, 256) 支持多主机模型、主或从操作 可…...

BOXTRADE-天启量化分析平台 主要功能介绍

BOXTRADE-天启量化分析平台 主要功能介绍 potato 数学 web 缘起 月晕而风&#xff0c;础润而雨 BOXTRADE-天启量化 欢迎来到天启量化&#xff01;这是一个专注于量化分析的网站。我们致力于为用户提供市场行情技术指标和量化策略分析方面的优质内容和资源。 我们的使命是 做…...

kaggle注册不显示验证码

edge浏览器 1.点击浏览器右上角三个点 2.点击扩展 3.点击管理扩展 4.点击获取Microsoft Edge扩展&#xff0c;在左上角输入Head Editor 5.输入https://www.azurezeng.com/static/HE-GoogleRedirect.json 6.下载后&#xff0c;点保存 成功&#xff01;...

python爬虫7:实战1

python爬虫7&#xff1a;实战1 前言 ​ python实现网络爬虫非常简单&#xff0c;只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点&#xff0c;方便以后复习。 申明 ​ 本系列所涉及的代码仅用于个人研究与讨论&#xff0c;并不会对网站产生不好…...

uniApp引入vant2

uniApp引入vant2 1、cnpm 下载&#xff1a;cnpm i vantlatest-v2 -S2、main.js文件引入 import Vant from ./node_modules/vant/lib/vant;Vue.use(Vant);3.app.vue中引入vant 样式文件 import /node_modules/vant/lib/index.css;...

如何大幅提高遥感影像分辨率(Python+MATLAB)

前言: 算法:NSCT算法(非下采样变换) 数据:Landsat8 OLI 遥感图像数据 编程平台:MATLAB+Python 论文参考:毛克.一种快速的全色和多光谱图像融合算法[J].测绘科学,2016,41(01):151-153+98.DOI:10.16251/j.cnki.1009-2307.2016.01.028. 左图:未进行融合的多光谱真彩色合…...

nginx php-fpm安装配置

nginx php-fpm安装配置 nginx本身不能处理PHP&#xff0c;它只是个web服务器&#xff0c;当接收到请求后&#xff0c;如果是php请求&#xff0c;则发给php解释器处理&#xff0c;并把结果返回给客户端。 nginx一般是把请求发fastcgi管理进程处理&#xff0c;fascgi管理进程选…...

通过ip获取地理位置信息

GeoLite2-City.mmdb 文件是 MaxMind 公司提供的一个免费的 IP 地址与城市地理位置映射数据库文件。它包含了 IP 地址范围与对应的城市、地区、国家、经纬度等地理位置信息的映射。这种数据库文件可以用于识别访问您的应用程序或网站的用户的地理位置&#xff0c;从而实现针对不…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...

前端调试HTTP状态码

1xx&#xff08;信息类状态码&#xff09; 这类状态码表示临时响应&#xff0c;需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分&#xff0c;客户端应继续发送剩余部分。 2xx&#xff08;成功类状态码&#xff09; 表示请求已成功被服务器接收、理解并处…...

ubuntu中安装conda的后遗症

缘由: 在编译rk3588的sdk时&#xff0c;遇到编译buildroot失败&#xff0c;提示如下&#xff1a; 提示缺失expect&#xff0c;但是实测相关工具是在的&#xff0c;如下显示&#xff1a; 然后查找借助各个ai工具&#xff0c;重新安装相关的工具&#xff0c;依然无解。 解决&am…...

Java中HashMap底层原理深度解析:从数据结构到红黑树优化

一、HashMap概述与核心特性 HashMap作为Java集合框架中最常用的数据结构之一&#xff0c;是基于哈希表的Map接口非同步实现。它允许使用null键和null值&#xff08;但只能有一个null键&#xff09;&#xff0c;并且不保证映射顺序的恒久不变。与Hashtable相比&#xff0c;Hash…...

LTR-381RGB-01RGB+环境光检测应用场景及客户类型主要有哪些?

RGB环境光检测 功能&#xff0c;在应用场景及客户类型&#xff1a; 1. 可应用的儿童玩具类型 (1) 智能互动玩具 功能&#xff1a;通过检测环境光或物体颜色触发互动&#xff08;如颜色识别积木、光感音乐盒&#xff09;。 客户参考&#xff1a; LEGO&#xff08;乐高&#x…...