二叉搜索树操作题目:删除二叉搜索树中的结点

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
      • 进阶
  • 解法一
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法二
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:删除二叉搜索树中的结点

出处:450. 删除二叉搜索树中的结点

难度

5 级

题目描述

要求

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

一般而言,删除结点可分为两个步骤:

  1. 首先找到需要删除的结点。
  2. 如果找到了需要删除的结点,删除该结点。

示例

示例 1:

示例 1.1

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

示例 1.2

示例 2:

输入: root   =   [5,3,6,2,4,null,7],   key   =   0 \texttt{root = [5,3,6,2,4,null,7], key = 0} root = [5,3,6,2,4,null,7], key = 0
输出: [5,3,6,2,4,null,7] \texttt{[5,3,6,2,4,null,7]} [5,3,6,2,4,null,7]
解释:二叉搜索树不包含值为 0 \texttt{0} 0 的结点。

示例 3:

输入: root   =   [],   key   =   0 \texttt{root = [], key = 0} root = [], key = 0
输出: [] \texttt{[]} []

数据范围

  • 树中结点数目在范围 [0,   10 4 ] \texttt{[0, 10}^\texttt{4}\texttt{]} [0, 104]
  • -10 5 ≤ Node.val ≤ 10 5 \texttt{-10}^\texttt{5} \le \texttt{Node.val} \le \texttt{10}^\texttt{5} -105Node.val105
  • 每个结点值各不相同
  • root \texttt{root} root 是二叉搜索树
  • -10 5 ≤ key ≤ 10 5 \texttt{-10}^\texttt{5} \le \texttt{key} \le \texttt{10}^\texttt{5} -105key105

进阶

树的高度为 h h h,你是否可以想出时间复杂度为 O ( h ) O(h) O(h) 的解法?

解法一

思路和算法

为了删除二叉搜索树中的结点,需要首先搜索待删除的结点,只有当待删除的结点存在时才需要执行删除结点的操作。

由于在二叉搜索树中搜索特定值的结点是一个递归的过程,因此可以使用递归实现删除结点的操作。递归的终止条件是当前结点为空,此时不需要删除任何结点,返回空二叉树。对于其余情况,比较根结点值和待删除的结点值,决定应该在根结点的哪个子树中删除结点,对该子树调用递归,并用递归调用的结果更新当前结点的相应子树。

  • 如果根结点值大于目标值,则应该在根结点的左子树中删除结点。

  • 如果根结点值小于目标值,则应该在根结点的右子树中删除结点。

  • 如果根结点值等于目标值,则需要删除根结点。判断根结点的左子结点和右子结点是否为空,分别执行相应的操作。

    • 如果根结点的两个子结点都为空,即根结点是叶结点,则直接删除根结点,返回空二叉树。

    • 如果根结点有一个子结点为空,则删除根结点之后剩下非空子树,返回根结点的非空子树。

    • 如果根结点的两个子结点都不为空,则找到根结点的后继结点,后继结点为根结点的右子树中的最右边的结点,将根结点值设为后继结点值,将后继结点设为其右子结点(需要通过对后继结点的父结点更新相应的子结点实现)。

代码

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if (root == null) {
            return null;
        }
        if (root.val > key) {
            root.left = deleteNode(root.left, key);
            return root;
        }
        if (root.val < key) {
            root.right = deleteNode(root.right, key);
            return root;
        }
        if (root.left == null && root.right == null) {
            return null;
        } else if (root.left == null) {
            return root.right;
        } else if (root.right == null) {
            return root.left;
        } else {
            TreeNode node = root.right, parent = root;
            while (node.left != null) {
                parent = node;
                node = node.left;
            }
            root.val = node.val;
            if (parent == root) {
                parent.right = node.right;
            } else {
                parent.left = node.right;
            }
            return root;
        }
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。时间复杂度取决于二叉搜索树的高度,最坏情况下二叉搜索树的高度是 O ( n ) O(n) O(n)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。空间复杂度主要是递归调用的栈空间,取决于二叉搜索树的高度,最坏情况下二叉搜索树的高度是 O ( n ) O(n) O(n)

解法二

思路和算法

递归实现可以改成迭代实现。首先在二叉搜索树中搜索待删除的结点,同时维护待删除的结点的父结点。如果待删除的结点不存在,则不执行删除操作,返回原二叉搜索树。

如果待删除的结点存在,则判断待删除的结点的父结点是否为空结点。如果待删除的结点的父结点为空,则待删除的结点为二叉搜索树的根结点,在整个二叉搜索树中执行删除操作;如果待删除的结点的父结点不为空,则在以待删除的结点为根结点的子树中执行删除操作,然后用执行删除操作之后的结果更新父结点的相应子树。

当原始二叉搜索树或者其中一个子树的根结点为待删除的结点时,删除操作如下。

  • 如果根结点的两个子结点都为空,即根结点是叶结点,则直接删除根结点,返回空二叉树。

  • 如果根结点有一个子结点为空,则删除根结点之后剩下非空子树,返回根结点的非空子树。

  • 如果根结点的两个子结点都不为空,则找到根结点的后继结点,后继结点为根结点的右子树中的最右边的结点,将根结点值设为后继结点值,将后继结点设为其右子结点(需要通过对后继结点的父结点更新相应的子结点实现)。

代码

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        TreeNode node = root, parent = null;
        while (node != null && node.val != key) {
            parent = node;
            if (node.val > key) {
                node = node.left;
            } else {
                node = node.right;
            }
        }
        if (node == null) {
            return root;
        }
        if (parent == null) {
            return deleteRoot(root);
        } else {
            if (node == parent.left) {
                parent.left = deleteRoot(node);
            } else {
                parent.right = deleteRoot(node);
            }
            return root;
        }
    }

    public TreeNode deleteRoot(TreeNode root) {
        if (root.left == null && root.right == null) {
            return null;
        } else if (root.left == null) {
            return root.right;
        } else if (root.right == null) {
            return root.left;
        } else {
            TreeNode parent = root, node = root.right;
            while (node.left != null) {
                parent = node;
                node = node.left;
            }
            root.val = node.val;
            if (node == parent.right) {
                parent.right = node.right;
            } else {
                parent.left = node.right;
            }
            return root;
        }
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。时间复杂度取决于二叉搜索树的高度,最坏情况下二叉搜索树的高度是 O ( n ) O(n) O(n)

  • 空间复杂度: O ( 1 ) O(1) O(1)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

关于JVM常见的十道面试题

方法区、永久代和元空间有什么区别&#xff1f; 方法区、永久区和元空间是Java虚拟机用于存储类信息的区域&#xff0c;它们在不同的Java虚拟机版本有所不同&#xff1a; 方法区&#xff1a;方法去是一块用于存储类的结构信息、常量、静态变量、即时编译器编译后的代码等数据…

5、应急响应-拒绝服务钓鱼识别DDOS压力测试邮件反制分析应用日志

目录 前言&#xff1a; 1、#内网应急-日志分析-爆破&横向&数据库 2、#红队APT-钓鱼邮件识别-内容&发信人&附件 3、#拒绝服务攻击-DDOS&CC-代理&防火墙防御 用途&#xff1a;个人学习笔记&#xff0c;欢迎指正&#xff01; 前言&#xff1a; 了解和…

opencv#41 轮廓检测

轮廓概念介绍 通常我们使用二值化的图像进行轮廓检测&#xff0c;对轮廓以外到内进行数字命名&#xff0c;如下图&#xff0c;最外面的轮廓命名为0&#xff0c;向内部进行扩展&#xff0c;遇到黑色白色相交区域&#xff0c;就是一个新的轮廓&#xff0c;然后依次对轮廓进行编号…

mac安装mysql的8.0设置面板启动不了

1、前言 记得之前安装mysql5.7的时候&#xff0c;是可以直接从设置里面的mysql面板启动的&#xff0c;但是到了mysql8.0之后就启动不了了&#xff0c;这个问题不知道是版本问题还是我换了m系列芯片的mysql导致的&#xff0c;之前很多次都启动不了&#xff0c;这次搞了下&#x…

sql注入,布尔盲注和时间盲注,无回显

布尔盲注 通过order by分组可以看到&#xff0c;如果正确会i显示you are in&#xff0c;错误则无任何提示&#xff0c;由此可以判断出&#xff0c;目前只显示对错&#xff0c;此外前端不会显示任何数据 也就是说&#xff0c;目前结果只有两种&#xff0c;在这种只有两种变量的…

三子棋游戏小课堂

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 今天的主菜是&#xff0c;C语言实现的三子棋小游戏&#xff0c; 所属专栏&#xff1a; C语言知识点 主厨的主页&#xff1a;Chef‘s blog 前言&…

在ubuntu22.04中借助docker实现安装、调试ros1.0

一.安装docker 参考&#xff1a;https://www.cnblogs.com/cqpanda/p/16247919.html 使用安装方法1直接安装&#xff0c;没出问题&#xff0c;我就继续了。出问题按方法2安装吧。 curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun 二.docker中安装ros1.…

101.对称二叉树

101.对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false提示&#xff1a; …

【C语言】epoll_wait / select

一、epoll_wait和select对比 1. 阻塞和非阻塞 在Linux C语言中进行socket编程时&#xff0c;epoll_wait 和 select 都是用于多路I/O复用的系统调用&#xff0c;但是它们的行为可以设置为阻塞和非阻塞模式&#xff0c;这取决于调用它们时所使用的参数。 让我们分别看看 epoll…

[网络安全] IIS----WEB服务器

一、 WEB服务器 WEB服务器 也叫网页服务器和 HTTP服务器使用协议: HTTP(端口:80) 或 HTTPS(端口443)浏览器:HTTP客户端网站: 一个或多个网页组成的集合 二、HTTP和HTTPS协议: HTTP : 是 HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09;的简写&#xff0c;…

Maven安装,学习笔记,详细整理maven的一些配置

Maven 1. 初识Maven 2. Maven概述 Maven模型介绍 Maven仓库介绍 Maven安装与配置 3. IDEA集成Maven 4. 依赖管理 01. Maven课程介绍 1.1 课程安排 学习完前端Web开发技术后&#xff0c;我们即将开始学习后端Web开发技术。做为一名Java开发工程师&#xff0c;后端 Web开发技术…

Solon 开源框架讲的“三源合一”是怎么回事?

1、什么是“三源合一”&#xff1f; “三源合一”&#xff0c;是 Solon 应用开发框架早期的一个架构想法。是指 Http、Socket、WebSocket 几个不同的通讯信号&#xff0c;进行统一架构处理…并且小巧。 对于 Socket 和 WebSocket&#xff0c;在原 消息监听 的模式之外增加了 M…

Wireshark网络协议分析 - Wireshark速览

在我的博客阅读本文 文章目录 1. 版本与平台2. 快速上手2.1. 选择网络接口进行捕获&#xff08;Capture&#xff09;2.2. 以Ping命令为例进行抓包分析2.3. 设置合适的过滤表达式2.4. 数据包详情2.5. TCP/IP 四层模型 3. 参考资料 1. 版本与平台 Wireshark是一个开源的网络数据…

vue——实现多行粘贴到table事件——技能提升

最近在写后台管理系统时&#xff0c;遇到一个需求&#xff0c;就是要从excel表格中复制多行内容&#xff0c;然后粘贴到后台系统中的table表格中。 如下图所示&#xff1a;一次性复制三行内容&#xff0c;光标放在红框中的第一个框中&#xff0c;然后按ctrlv粘贴事件&#xff0…

机器学习复习(6)——numpy的数学操作

加减法运算 # 创建两个不同的数组 a np.arange(4) #list(0,1,2,3 b np.array([5,10,15,20]) # 两个数组做减法运算 b-a 运行结果&#xff1a; 计算数组的平方 #b*2代表数组b每个元素乘以2 #b**2代表数组b每个元素的2次方 b**2 运行结果&#xff1a; 计算数组的正弦值 #…

简单高效 Learn LaTeX 013 - LaTex FloatingBody Tables (44 mins) 浮动体表格

浮动体是LaTex中的一个重要概念&#xff0c;这个视频演示了以浮动体为载体的表格的排版应用。 https://www.douyin.com/user/self?modal_id7305874487138913574&showTabpost

机器学习的精髓-梯度下降算法

目 1. 梯度下降算法2. 梯度下降求解3. 总结 1. 梯度下降算法 梯度下降算法是一种优化算法&#xff0c;用于最小化函数的数值方法。它通过沿着函数梯度的反方向来更新参数&#xff0c;以逐步减小函数值。这一过程重复进行直到达到收敛条件。梯度下降算法有多种变体&#xff0c;…

02、全文检索 ------ Solr(企业级的开源的搜索引擎) 的下载、安装、Solr的Web图形界面介绍

目录 Solr 的下载和安装Solr的优势&#xff1a;Lucene与Solr 安装 Solr1、下载解压2、添加环境变量3、启动 Solr Solr 所支持的子命令&#xff1a;Solr 的 Core 和 Collection 介绍Solr 的Web控制台DashBoard&#xff08;仪表盘&#xff09;Logging&#xff08;日志&#xff09…

vscode 插件 Tailwind CSS IntelliSense 解决 class 提示问题

问题描述&#xff1a; 如下写js字符串是没有class智能提示的&#xff1a; const clsName bg-[#123456] text-[#654321] return <div className{clsName}></div>解决方案&#xff1a; 安装 clsx 依赖 pnpm i clsx设置 vscode 的 settings.json {"tailwin…

150基于matlab的凸轮轮廓的设计计算与绘图计算此结构的最优化参数

基于matlab的凸轮轮廓的设计计算与绘图计算此结构的最优化参数&#xff0c;根据其原理输出推程和回程的最大压力角、最小曲率半径等相关结果。程序已调通&#xff0c;可直接运行。 150 凸轮轮廓的设计 结构的最优化参数 (xiaohongshu.com)