leetcode题解450:删除BST中的结点!调整二叉树的结构最难!

一、题目内容

题目要求删除二叉搜索树(BST)中值为 key 的节点,并保证删除后二叉搜索树的性质不变。返回删除节点后的二叉搜索树的根节点的引用。一般来说,删除节点可分为两个步骤:首先找到需要删除的节点;如果找到了,删除它。

二、题目分析

(一)输入和输出

输入:二叉搜索树的根节点 root 和待删除的值 key。

输出:删除指定值节点后二叉搜索树的根节点。

(二)递归函数 deleteNode 的逻辑

基本情况:如果当前节点为空(root == NULL),说明没有找到需要删除的节点,直接返回 NULL。

如果当前节点的值等于 key(root->val == key),则需要根据当前节点的子节点情况来决定如何删除:

  1. 如果当前节点是叶子节点(root->left == NULL && root->right == NULL),直接删除当前节点并返回 NULL。

  2. 如果当前节点只有一个右子节点(root->left == NULL && root->right != NULL),删除当前节点并返回其右子节点。

  3. 如果当前节点只有一个左子节点(root->left != NULL && root->right == NULL),删除当前节点并返回其左子节点。

  4. 如果当前节点既有左子节点又有右子节点,找到当前节点右子树的最左节点(即右子树中的最小值节点),将其左子树连接到该最左节点的左子树上,然后删除当前节点并返回其右子节点。

递归逻辑:如果当前节点的值大于 key(root->val > key),则递归地在左子树中删除 key 对应的节点;如果当前节点的值小于 key(root->val < key),则递归地在右子树中删除 key 对应的节点。递归返回后,将返回的子树节点赋值给当前节点的左或右子节点。

三、解题要点

(一)二叉搜索树的定义

二叉搜索树是一种特殊的二叉树,其性质是:对于任意节点,其左子树上所有节点的值都小于该节点的值,其右子树上所有节点的值都大于该节点的值。这一性质是删除操作的基础,删除操作需要保持这一性质不变。

(二)删除操作的性质

删除操作需要保持二叉搜索树的性质不变。删除节点后,树的结构需要重新调整,以确保仍然满足二叉搜索树的性质。

(三)解题思路

1.基本情况

如果当前节点为空(root == NULL),说明没有找到需要删除的节点,直接返回 NULL。这是递归的终止条件。

2.递归逻辑

比较当前节点值与待删除值:

如果当前节点的值等于 key(root->val == key),根据当前节点的子节点情况来决定如何删除。

如果当前节点的值大于 key(root->val > key),则递归地在左子树中删除 key 对应的节点。

如果当前节点的值小于 key(root->val < key),则递归地在右子树中删除 key 对应的节点。

更新子树:递归返回后,将返回的子树节点赋值给当前节点的左或右子节点。这一步确保了递归返回后,当前节点的子树被正确更新。

3.递归返回

递归返回时,返回当前节点。这一步确保了递归调用的正确性,使得每次递归返回后,当前节点的状态被正确恢复,不会影响后续的递归调用。

四、代码解答

class Solution {
public:TreeNode* deleteNode(TreeNode* root, int key) {// 如果当前节点为空,直接返回 NULLif (root == NULL) return NULL;// 如果当前节点的值等于 key,根据子节点情况决定如何删除if (root->val == key) {// 如果当前节点是叶子节点,直接删除并返回 NULLif (root->left == NULL && root->right == NULL) {delete root;return NULL;}// 如果当前节点只有一个右子节点,删除当前节点并返回其右子节点else if (root->left == NULL && root->right != NULL) {TreeNode* temp = root->right;delete root;return temp;}// 如果当前节点只有一个左子节点,删除当前节点并返回其左子节点else if (root->left != NULL && root->right == NULL) {TreeNode* temp = root->left;delete root;return temp;}// 如果当前节点既有左子节点又有右子节点else {// 找到当前节点右子树的最左节点TreeNode* cur = root->right;while (cur->left != NULL) {cur = cur->left;}// 将当前节点的左子树连接到最左节点的左子树上cur->left = root->left;// 删除当前节点并返回其右子节点TreeNode* temp = root->right;delete root;return temp;}}// 如果当前节点的值大于 key,递归地在左子树中删除 key 对应的节点if (root->val > key) {root->left = deleteNode(root->left, key);}// 如果当前节点的值小于 key,递归地在右子树中删除 key 对应的节点else {root->right = deleteNode(root->right, key);}// 返回当前节点return root;}
};

五、详细注释

(一)递归函数 deleteNode

基本情况:如果当前节点为空,直接返回 NULL。

如果当前节点的值等于 key,根据当前节点的子节点情况来决定如何删除。

递归逻辑:如果当前节点的值大于 key,递归地在左子树中删除 key 对应的节点;如果当前节点的值小于 key,递归地在右子树中删除 key 对应的节点。递归返回后,将返回的子树节点赋值给当前节点的左或右子节点。

六、回溯和递归的详细解释

(一)递归

递归是一种函数调用自身的方法,用于解决复杂问题。在本题中,递归用于逐层检查每个节点,找到需要删除的节点,并根据情况调整树的结构。递归的核心思想是将问题分解为更小的子问题,通过解决子问题来解决原问题。

(二)终止条件

递归的终止条件是当前节点为空,此时直接返回 NULL。这是递归的出口,确保递归不会无限进行下去。

(三)回溯

在递归调用返回后,通过返回值恢复到当前节点的状态,确保每次递归返回后,状态正确,不会影响后续的递归调用。

在本题中,回溯的过程主要体现在以下几个方面:

  1. 递归调用的返回值:每个递归分支都会返回一个节点,这个节点可以是删除操作后的子树的根节点,也可以是 NULL。

  2. 返回值的处理:在每个递归调用返回后,当前节点会根据返回值来决定下一步的操作:

    • 如果当前节点的值大于 key,将返回值赋值给当前节点的左子节点。

    • 如果当前节点的值小于 key,将返回值赋值给当前节点的右子节点。

(四)递归调用的详细过程

  1. 初始调用:从根节点开始调用 deleteNode(root, key)。

  2. 递归调用:如果 root->val > key,递归调用 deleteNode(root->left, key);如果 root->val < key,递归调用 deleteNode(root->right, key)。

  3. 终止条件:当递归调用到达一个空节点时,直接返回 NULL。

  4. 回溯过程:递归返回后,将返回的子树节点赋值给当前节点的左或右子节点。递归返回到上一层调用,继续处理上一层的节点,直到返回到根节点。

(五)代码执行过程示例

假设我们有一个二叉搜索树,根节点为 root,值为 5,其左子节点值为 3,右子节点值为 7。现在要删除值为 3 的节点。

  1. 初始调用:deleteNode(root, 3)。

  2. 当前节点值为 5,3 < 5,递归调用 deleteNode(root->left, 3)。

  3. 递归调用:deleteNode(root->left, 3)。

  4. 当前节点值为 3,3 == 3,进入删除逻辑:

    • 当前节点只有一个左子节点,删除当前节点并返回其左子节点。

  5. 回溯过程:

    • 返回到 root,将返回的左子节点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/86554.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

让 Kubernetes (K8s) 集群 使用 GPU

要让 Kubernetes (K8s) 集群 使用 GPU&#xff0c;并且节点是 KVM 虚拟化 出来的&#xff0c;需要确保以下几点&#xff1a; KVM 虚拟机透传 GPU&#xff08;PCIe Passthrough&#xff09; 宿主机和 K8s 节点正确安装 NVIDIA 驱动 K8s 集群安装 nvidia-device-plugin Pod 配…

Android第十七次面试总结(Java数据结构)

一、Java 集合体系核心架构与高频考点 1. 集合体系架构图 Java集合框架 ├─ Collection&#xff08;单列集合&#xff09; │ ├─ List&#xff08;有序、可重复&#xff09; │ │ ├─ ArrayList&#xff08;动态数组&#xff0c;随机访问快&#xff09; │ │ ├─…

Linux 删除登录痕迹

本文介绍相对彻底的删除 Linux 的登录痕迹&#xff0c;操作前确保已经可以拿到能提权ROOT令牌的系统管理权限。 当然&#xff0c;仍可以先查阅以下文章。 Linux 删除用户终端命令行操作记录-CSDN博客 1、清楚当前会话记录 history -c # 清空当前终端内存中的历史命令 2、永…

Lighttpd 配置选项介绍

根据提供的 Lighttpd 配置选项文档&#xff08;https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ConfigurationOptions &#xff09;&#xff0c;以下是所有配置选项的详细解释、作用及适用场景&#xff0c;按模块分组说明&#xff1a; 以下是对 Lighttpd 配置选项 …

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…

Python 训练营打卡 Day 40-训练和测试的规范写法

一.单通道图片的规范写法 以之前的MNIST数据集为例 import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader , Dataset # DataLoader 是 PyTorch 中用于加载数据的工具 from torchvision import datasets, transforms # t…

Java 枚举(Enum)的使用说明

在 Java 中&#xff0c;枚举&#xff08;Enum&#xff09;是一种特殊的数据类型&#xff0c;用于定义一组固定的命名常量。它比传统的常量&#xff08;如 public static final&#xff09;更安全、更灵活&#xff0c;且支持面向对象特性。以下是枚举的详细用法&#xff1a; 1. …

Docker部署Nginx-UI

使用如下命令拉取运行nginx-ui软件 docker run -dit \ --namenginx-ui \ --restartalways \ -e TZAsia/Shanghai \ -v /mnt/user/appdata/nginx:/etc/nginx \ -v /mnt/user/appdata/nginx-ui:/etc/nginx-ui \ -v /var/run/docker.sock:/var/run/docker.sock \ -…

OkHttp 3.0源码解析:从设计理念到核心实现

本文通过深入分析OkHttp 3.0源码&#xff0c;揭示其高效HTTP客户端的实现奥秘&#xff0c;包含核心设计理念、关键组件解析、完整工作流程及实用技巧。 一、引言&#xff1a;为什么选择OkHttp&#xff1f; 在Android和Java生态中&#xff0c;OkHttp已成为HTTP客户端的标准选择…

洛谷P12170 [蓝桥杯 2025 省 Python B] 攻击次数

题目传送门 思路 首先定义一个数 n n n ,初值为 2025 2025 2025,从第一回合开始,三个英雄持续攻击,攻击方式为: 第一个英雄: 每回合攻击 5 5 5

百度之星2021——BD202104 萌新

输入格式&#xff1a; 本题有多组测试数据。 第一行一个数 T (1 ≤ T ≤ 1000) 表示一共有 T 组数据。对于每一组数据&#xff0c;输入一行两个数 a,b (1 ≤ a,b ≤ 1000000000)。 输出格式&#xff1a; 对每组数据&#xff0c;输出一行两个数分别表示最小与最大的 c&#xff0…

R语言ICU患者死亡率预测实战

【图书推荐】《R语言医学数据分析实践》-CSDN博客 《R语言医学数据分析实践 李丹 宋立桓 蔡伟祺 清华大学出版社9787302673484》【摘要 书评 试读】- 京东图书 (jd.com) 预测ICU患者死亡率对比较药物的疗效、比较护理的有效性、比较手术的有效性有重要意义&#xff0c;利用机…

leetcode240-搜索二维矩阵

leetcode 240 思路 1. 矩阵特性 首先&#xff0c;利用矩阵的特性是解题的关键&#xff1a; 每行的元素递增每列的元素递增 这意味着&#xff0c;如果我们在矩阵中从右上角或左下角开始搜索&#xff0c;可以有效缩小搜索范围 2. 从右上角开始搜索 将搜索的起点定位在矩阵…

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…

【web应用】若依框架:若依框架中的页面跳转简介

文章目录 ⭐前言1. 后端控制器跳转2. 前端路由跳转3. 菜单配置跳转4. 权限控制跳转5. 常见跳转路径 ⭐一、主目录页面跳转⭐二、菜单目录跳转⭐总结 标题详情作者JosieBook头衔CSDN博客专家资格、阿里云社区专家博主、软件设计工程师博客内容开源、框架、软件工程、全栈&#x…

MS9292+MS9332 HD/DVI转VGA转换器+HD环出带音频

MS9292MS9332是一款HD/DVI转VGA转换器HD环出带音频的视频转换方案。支持HD/DVI输入&#xff0c;VGA输出和HD环出&#xff0c;HD/DVI输入最高支持1920120060Hz&#xff0c;VGA输出最高支持1920120060Hz&#xff0c;HD环出最高支持4K30Hz。该方案已实现量产&#xff0c;并提供完善…

C++初阶-list的模拟实现(难度较高)

1.list&#xff08;容器&#xff0c;不是类&#xff09;模拟实现基本结构 这个实现是和源码的实现不同的&#xff0c;不要进行强制类型转换了&#xff0c;很麻烦。我们把定义放在.h文件中&#xff0c;在.cpp中放测试代码。 注&#xff1a;这个基本结构之后会改变&#xff0c;…

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…

【iOS】cell的复用以及自定义cell

【iOS】cell的复用以及自定义cell 文章目录 【iOS】cell的复用以及自定义cell前言cell的复用手动&#xff08;非注册&#xff09;自动&#xff08;注册&#xff09; 自定义cell 前言 cell的复用及自定义cell是UITableView或UICollectionView的一个重要优化机制,当用户滚动视图…

深度学习之模型压缩三驾马车:基于ResNet18的模型剪枝实战(2)

前言 《深度学习之模型压缩三驾马车&#xff1a;基于ResNet18的模型剪枝实战&#xff08;1&#xff09;》里面我只是提到了对conv1层进行剪枝&#xff0c;只是为了验证这个剪枝的整个过程&#xff0c;但是后面也有提到&#xff1a;仅裁剪 conv1层的影响极大&#xff0c;原因如…