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

news2024/10/5 14:20:10

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)。

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

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

相关文章

AJ-Captcha行为验证在vue中的使用

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 项目场景&#xff1a;由原先的验证码校验升级为行为验证校验 使用方法 提示&#xff1a;参考文档&#xff1a; 参考文档&#xff1a;vue使用AJ-Captcha文档 gitee地址&#xff1a;AJ-Captcha &…

【Apollo】Apollo版本变迁里程碑

特点与改进 概述里程碑6.0版本特点及改进7.0版本特点及改进8.0版本特点及改进代码差异 主页传送门&#xff1a;&#x1f4c0; 传送 概述 Apollo (阿波罗)是一个开放的、完整的、安全的平台&#xff0c;将帮助汽车行业及自动驾驶领域的合作伙伴结合车辆和硬件系统&#xff0c;快…

python3ide手机安卓版下载,python3下载手机安卓版

本篇文章给大家谈谈python3ide手机安卓版下载&#xff0c;以及python3下载手机安卓版&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 python3是一个在Android上运行Python3脚本引擎&#xff0c;python3整合了Python3解释器、Console、编辑器和SL4A库PHP与PYT…

智慧城市能实现嘛?数字孪生又在其中扮演什么角色?

数字孪生智慧城市是将数字孪生技术与城市智能化相结合的新兴概念&#xff0c;旨在通过实时数字模拟城市运行&#xff0c;优化城市管理与服务&#xff0c;创造更智能、高效、可持续的城市环境。 在智慧城市中&#xff0c;数字孪生技术可以实时收集、分析城市各个方面的数据&…

如何安装合适的显卡驱动,如何安装合适的驱动

大家好&#xff0c;小编为大家解答如何安装合适的松紧裤腰大房子呢的问题。很多人还不知道如何安装合适的显卡驱动版本&#xff0c;现在让我们一起来看看吧&#xff01; 1.准备好安装包 1&#xff09;上python官网下载python运行环境&#xff08;Download Python | Python.org&…

seaborn color palette 调色板颜色图

Here is a list of the Color Brewer palettes, with their names for easy reference: sns.lineplot(datanormal_df, palettesns.color_palette(paletteSet1, n_colors1))

KaiwuDB CTO 魏可伟:回归用户本位,打造“小而全”的数据库

8月16日&#xff0c;KaiwuDB 受邀亮相第十四届中国数据库技术大会 DTCC 2023。KaiwuDB CTO 魏可伟接受大会主办方的采访&#xff0c;双方共同围绕“数据库架构演进、内核引擎设计以及不同技术路线”展开深度探讨。 以下是采访的部分实录 ↓↓↓ 40 多年前&#xff0c;企业的数…

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

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

飞凌嵌入式邀您共聚2023深圳国际电子展(elexcon 2023)

8月23~25日&#xff0c;Elexcon 2023深圳国际电子展将在深圳会展中心&#xff08;福田&#xff09;举行&#xff0c;届时飞凌嵌入式将携多款重量级产品及热门行业解决方案亮相&#xff0c;展位号1Z55。飞凌嵌入式将聚焦5G、人工智能、智慧交通、智慧医疗、智慧电力、工业物联网…

PDF怎么转换成PPT?这个工具太好用了

pdf和ppt是常用的文档格式&#xff0c;只是功能不同&#xff0c;应用场景略有不同。pdf安全稳妥&#xff0c;更加适合文件阅读、传输和保存&#xff0c;ppt则多用于工作总结、产品宣传&#xff0c;更加生动形象&#xff0c;容易理解。有时候我们需要把pdf转换成ppt&#xff0c;…

PSP - 基于扩散生成模型预测蛋白质结构 EigenFold 算法与环境配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132357976 Paper: EigenFold: Generative Protein Structure Prediction with Diffusion Models EigenFold 是用于蛋白质结构预测的扩散生成模型…

Windows系统提权(二)

Windows系统服务漏洞 Always Install Elevated-总是以高权限安装 AlwaysInstallElevated是一个策略设置&#xff0c;当在系统中使用Windows Installer安装任何程序时&#xff0c;该参数允许非特权用户以system权限运行MSI文件。如果目标系统上启用了这一设置&#xff0c;我们…

Web菜鸟入门教程 - Swagger实现自动生成文档

如果是一个人把啥都开发了&#xff0c;那用不到Swagger-UI&#xff0c;但一般情况是前后端分离的&#xff0c;所以就需要告诉前端开发人员都有哪些接口&#xff0c;传入什么参数&#xff0c;怎么调用&#xff0c;返回什么。有了Swagger-UI就能把这部分文档编写的业务给省去了。…

抓洞指南- drupal1 代码执行 (CVE-2018-7600)

一个非常憨逼的事情&#xff0c;就是不知道flag在哪&#xff0c;然后突发奇想&#xff0c;既然把指令都能执行命令&#xff0c;如果直接ls /tmp,然后数据就拿到手了。这地方卡了我很久&#xff0c;看了很多教程感觉都不一样。 POST /user/register?element_parentsaccount/ma…

问道管理:沪指震荡微跌,保险、银行板块拉升,环保板块表现活跃

18日早盘&#xff0c;两市股指盘中震动回落&#xff0c;沪指翻绿&#xff0c;深成指、创业板指均走低&#xff1b;北向资金继续大幅流出&#xff0c;半日净卖出近50亿元。 截至午间收盘&#xff0c;沪指微跌0.06%报3161.97点&#xff0c;深成指跌0.69%&#xff0c;创业板指跌0.…

09 - 网络通信优化之序列化:避免使用Java序列化

当前大部分后端服务都是基于微服务架构实现的。服务按照业务划分被拆分&#xff0c;实现了服务的解偶&#xff0c;但同时也带来了新的问题&#xff0c;不同业务之间通信需要通过接口实现调用。两个服务之间要共享一个数据对象&#xff0c;就需要从对象转换成二进制流&#xff0…

216、仿真-基于51单片机温度烟雾人体感应布防报警Proteus仿真设计(程序+Proteus仿真+原理图+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、原理图 五、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选…

【MT32F006】MT32F006之CS1237采集秤传感器

本文最后修改时间&#xff1a;2023年06月07日 一、本节简介 本文介绍如何使用MT32F006连接CS1237芯片采集秤传感器。 二、实验平台 库版本&#xff1a;V1.0.0 编译软件&#xff1a;MDK5.37 硬件平台&#xff1a;MT32F006开发板&#xff08;主芯片MT32F006&#xff09; 仿真…

北斗时空子链重磅发布!移远通信与中国移动携手打造更加可靠的高精定位产品

8月16日&#xff0c;以“百川聚申城 数智创未来”为主题的2023年中国移动上海产业研究院百川生态大会在上海隆重召开。 本次大会聚焦时空信息、数智交通、工业能源、金融科技等领域&#xff0c;各级领导、产学研专家、企业家共聚一堂&#xff0c;共谋产业、共话行业、共促发展。…

innovus: IMPSP-190 利用率超标,place中断问题

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 这个问题在查看manual之后&#xff0c;工具给出两个解释。一个是setPlaceMode -place_global_max_density $value(0-1)设置的太小了&#xff0c;另一个是place之前加了过量的so…