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

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,将返回的左子节点

相关文章:

  • DiffBP: generative diffusion of 3D molecules for target protein binding
  • 利用Seagate service获得system shell
  • 什么样的登录方式才是最安全的?
  • 安全大模型智驱网络和数据安全效能跃迁
  • [Java基础] stream流中Collectors.toMap报空指针异常情况
  • CentOS7.9 查询运维安全日志,排查恶意用户
  • Oraclede 的体系结构
  • V837s-调整内核dmesg内容ring buffer大小
  • 调用支付宝接口响应40004 SYSTEM_ERROR问题排查
  • 标准 IO 流- Rust 标准输入 stdin 与 C/C++ 标准输入(Standard I/O Input)对比分析
  • iview组件库:自定义方法去控制Tree树形数据的根节点与叶节点的关联性
  • Vim 高亮命令完整学习笔记
  • 看板任务描述不清如何解决
  • Blogx项目配置文件读取流程详解
  • coze的基本使用
  • 【使用LLM搭建系统】7 搭建一个带评估的端到端问答系统
  • 第6章 方法 笔记
  • 自动化三维扫描检测赋能汽车铸造件高效检测
  • 【Flash 芯片 MTD 专栏】Flash芯片识别异常导致mtd子系统分区创建失败
  • 「Java基本语法」运算符与表达式
  • 代刷网站只做软件吗/网站优化名词解释
  • 做新闻类网站/如何建立自己的网页
  • 政府网站建设推进会上的讲话/软文代写接单平台
  • 昆明网站做的好的公司简介/互联网营销师培训机构哪家好
  • 邢台专业网站建设/微信5000人接推广费用
  • 淮安做网站服务单位/seo排名平台