代码随想录算法训练营第二二天| 二叉搜索树的最近公共祖先、二叉搜索树中的插入操作、删除二叉搜索树中的节点

目录

  • 二叉搜索树的最近公共祖先
  • 二叉搜索树中的插入操作
  • 删除二叉搜索树中的节点
  • 普通二叉树的删除方式

LeetCode 235. 二叉搜索树的最近公共祖先
LeetCode 701.二叉搜索树中的插入操作
LeetCode 450.删除二叉搜索树中的节点

二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

如果 中间节点是 q 和 p 的公共祖先,那么 中节点的数组 一定是在 [p, q]区间的。即 中节点 > p && 中节点 < q 或者 中节点 > q && 中节点 < p。

且当我们从上向下去递归遍历,第一次遇到 cur节点是数值在[q, p]区间中,那么cur就是 q和p的最近公共祖先。

p、q 为不同节点且均存在于给定的二叉搜索树中。→ 省去了判断是否为 null 的操作。

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {// if (root == null) return root; // 因为p、q 为不同节点且均存在于给定的二叉搜索树中,所以不用判断// TreeNode left = lowestCommonAncestor(root.left, p, q); if (left != null) return left; // 因为p、q 为不同节点且均存在于给定的二叉搜索树中,所以不用判断if (root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q);if (root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q);return root;}
}
class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {while (true) {if (root.val > p.val && root.val > q.val) {root = root.left;} else if (root.val < p.val && root.val < q.val) {root = root.right;} else {break;}}return root;}
}

二叉搜索树中的插入操作

给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。

注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。

只要遍历二叉搜索树,找到空节点 插入元素就可以了。

终止条件就是找到遍历的节点为null的时候,就是要插入节点的位置了,并把插入的节点返回。

这里把添加的节点返回给上一层,就完成了父子节点的赋值操作了。

把新的节点返回给上一层,上一层就要用 root->left 或者 root->right接住

class Solution {TreeNode pre = null;TreeNode cur = null;public TreeNode insertIntoBST(TreeNode root, int val) {if (root == null) {TreeNode node = new TreeNode(val);return node;}if (root.val > val) root.left = insertIntoBST(root.left, val);if (root.val < val) root.right = insertIntoBST(root.right, val);return root;}}
class Solution {public TreeNode insertIntoBST(TreeNode root, int val) {if (root == null) return new TreeNode(val);TreeNode newRoot = root;TreeNode pre = root;while (root != null) {pre = root;if (root.val > val) {root = root.left;} else if (root.val < val) {root = root.right;}}if (pre.val > val) {pre.left = new TreeNode(val);} else {pre.right = new TreeNode(val);}return newRoot;}
}

删除二叉搜索树中的节点

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

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

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

在这里插入图片描述

二叉搜索树中删除节点遇到的情况:

  1. 没找到删除的节点,遍历到空节点直接返回

  2. 找到删除的节点

    2.1 左右孩子都为空(叶子节点), 直接删除节点,返回 null 为根节点

    2.2 删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点

    2.3 删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点

    2.4 左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。

class Solution {public TreeNode deleteNode(TreeNode root, int key) {if (root == null) return root;  // 第一种情况:没找到删除的节点,遍历到空节点直接返回了if (root.val == key) {     // 内含第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点if (root.left == null) {   // 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点return root.right;} else if (root.right == null) {  // 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点return root.left;} else {// 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置// 并返回删除节点右孩子为新的根节点。TreeNode cur = root.right;   // 找右子树最左面的节点while (cur.left != null) {cur = cur.left;}cur.left = root.left;   // 把要删除的节点(root)左子树放在cur的左孩子的位置root = root.right;      // 返回旧root的右孩子作为新rootreturn root;}}if (root.val > key) root.left = deleteNode(root.left, key);if (root.val < key) root.right = deleteNode(root.right, key);return root;}
}

二叉搜索树添加节点只需要在叶子上添加就可以的,不涉及到结构的调整,而删除节点操作涉及到结构的调整。

普通二叉树的删除方式

普通二叉树的删除方式(没有使用搜索树的特性,遍历整棵树),用交换值的操作来删除目标节点。

代码中目标节点(要删除的节点)被操作了两次:

第一次是和目标节点的右子树最左面节点交换。

第二次直接被NULL覆盖了。

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

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

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

相关文章

windows安装oracle之后怎么连接使用

目录 1.打开SQl Developer 2.选择JDK 3.登录 4.创建表空间,用户 安装oracle的详细教程 WINDOWS安装Oracle11.2.0.4-CSDN博客 1.打开SQl Developer 找到 SQl Developer 2.选择JDK 根据你安装的oracle版本,因为我的oracle是安装的32位的,所以这里jdk也要选择32位 选择到ja…

1.迭代与递归 - JS

迭代与递归是函数进阶的第一个门槛。迭代就是对已知变量反复赋值变换&#xff1b;递归就是函数体内调用自身。 迭代 一个迭代是就是一个循环&#xff0c;根据迭代式对变量反复赋值。 求近似根&#xff08;切线法&#xff09;&#xff1b; 迭代描述&#xff1a; x 0 x_0 x0…

Docker核心教程

1. 概述 官网&#xff1a;https://docs.docker.com/ Docker Hub 网站&#xff1a;https://hub.docker.com/ 容器较为官方的解释&#xff1a; 一句话概括容器&#xff1a;容器就是将软件打包成标准化单元&#xff0c;以用于开发、交付和部署。 容器镜像是轻量的、可执行的独立…

Threejs API——`OrbitControls`相机控件

文章目录 API用法API OrbitControls 相机控制用法 导入import {OrbitControls } from three/examples/jsm/controls/OrbitControls.js import {DRACOLoader,AmbientLight,Color,MOUSE,

Java项目要不要部署在Docker里?

部署Java项目有很多种方式&#xff0c;传统的方式是直接在物理机或虚拟机上部署应用&#xff0c;但为什么现在容器化部署变得越来越流行&#xff0c; 个人觉得原因有以下几个&#xff1a; 1、 环境一致性&#xff1a;使用Docker可以确保开发、测试和生产环境的一致性&#xff…

传感器类总结(一)MPU9250 3-2程序关于IIC的底层程序

关于IIC的逻辑和底层协议可以看之前总结的 #IIC 通信协议 1、读写数据 1.1、写数据 发送N个字节程序的流程: 1、发送起始信号 2、发送从机地址和写 3、等待从机发回应答信号 4、发送第一字节数据 等待应答 5、发送下一字节数据 等带应答或非应答信号 6、发送停止信号停止发送…

D365:Debug

文章目录 前言一、附加进程二、选择进程三、DebugDebug进ApplicationSuite文件方法一方法二 前言 使用 Visual Studio 调试 D365 一、附加进程 点击路径 Debug > Attach to Process 二、选择进程 勾选下面的Show processes from all users,选择w3wp.exe&#xff0c;点击At…

#nlp|jieba分词词性对照

jieba词性对照表 a 形容词 ad 副形词 ag 形容词性语素 an 名形词 b 区别词 c 连词 d 副词 df dg 副语素 e 叹词 f 方位词 g 语素 h 前接成分 i 成语 j 简称略称 k 后接成分 l 习用语 m 数词 mg mq 数量词 n 名词 ng 名词性语素 nr 人名 nrfg nrt ns 地名 nt 机构团体名 nz 其他…

HCIA学习第六天:OSPF:开放式最短路径优先协议

OSPF&#xff1a;开放式最短路径优先协议 无类别链路状态IGP动态路由协议 1.距离矢量协议&#xff1a;运行距离矢量协议的路由器会周期性的泛洪自己的路由表。通过路由的交互&#xff0c;每台路由器从相邻的路由器学习到路由&#xff0c;并且加载进自己的路由表中&#xff1b…

git学习及简单maven打包

前提&#xff1a; 已经有远程仓库地址 和账号密码了 已经安装git了 1.本地新建文件夹A用作本地仓库 2.在A文件夹下右键打开GIT BASH HERE 3.创建用户和密码&#xff0c;方便追踪提交记录 git config --global user.email “caoqingqing0108” //创建邮箱 git config --global …

电视盒子哪款好?年货节必看电视盒子排名

电视盒子哪款好&#xff1f;电视盒子是每天都会使用到的&#xff0c;和电视机是好搭档&#xff0c;但很多朋友买电视盒子的时候会踩雷&#xff0c;像虚标配置、偷工减料、无售后等&#xff0c;近来年货节大促购入电视盒子的消费者增多&#xff0c;小编这次要来分享的是好评度最…

centos搭建ftp踩坑记录

ftp服务器搭建参考b站视频 第1坑&#xff0c;开放端口后仍然无法连接&#xff1a; 这里不仅需要在防火墙打开20和21端口&#xff0c;还需要打开被动访问所使用的端口&#xff0c;也就是在配置文件vsftpd.conf中指定的被动访问接收端口。 pasv_enableYES pasv_min_port40000 p…

【Java】Springboot入门

学习目标 基于SpringBoot框架的程序开发步骤 熟练使用SpringBoot配置信息修改服务器配置 基于SpringBoot的完成SSM整合项目开发 一、SpringBoot简介 1. 入门案例 问题导入 SpringMVC的HelloWord程序大家还记得吗&#xff1f; SpringBoot是由Pivotal团队提供的全新框架&…

了解维特比算法:通信系统和自然语言处理中解码的基石

一、介绍 在数字通信和信号处理领域&#xff0c;维特比算法是一种革命性的纠错和解码方法。该算法以 1967 年推出的 Andrew Viterbi 的名字命名&#xff0c;已成为数字通信和自然语言处理领域的基础。本文旨在深入研究维特比算法的复杂性&#xff0c;探讨其理论基础、实际应用以…

四、ESP8266网络客户端

四、ESP8266网络客户端 基本操作1、[使用ESP8266HTTPClient库实现网络通讯](https://blog.csdn.net/X_King_Q/article/details/112061397)2、使用WiFiClient库实现网络通讯3、Stream4、HTTP协议数据通讯4.1客户端向服务器发送数据信息4.2客户端向服务器请求数据信息 基本操作 …

2401cmake,学习cmake1

1步:一个基本出发点 最基础项目是基于源码的一个可执行构建.对简单项目.三行CMakeLists.txt就满足了. 在步1路径下创建如下CMakeLists.txt文件: cmake_minimum_required(VERSION 3.10) //设置项目名 project(Tutorial) //添加可执行文件 add_executable(Tutorial tutorial.cx…

跨境电商展-2024广州跨境电商展览会(ICBE China 2024)

ICBE2024第11届广州国际跨境电商交易博览会&#xff0c;作为华南地区最具影响力的跨境电商展览会&#xff0c;将再次于2024年5月15-17日在广州保利世贸展览馆盛大举行。此次展会以“创新、合作、共赢”为主题&#xff0c;汇聚了来自全球各地的跨境电商企业、平台、服务商等&…

(2024,定性评估、定量评估、人类评估)神经风格转移评估:综述

Evaluation in Neural Style Transfer: A Review 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 1. 简介 2. 神经风格转移方法 0. 摘要 神经风格转移&#xff08;Neural St…

LeetCode.2808. 使循环数组所有元素相等的最少秒数

题目 题目链接 分析 我们最终形成的数组一定是当前数组nums 中的一个数字。 所以我们的想法就是枚举数组 nums 中的所有数字&#xff0c;取最小值。 题目告诉我们每一秒都可以向左右扩散一位&#xff0c;那么多个相同的 x 同时扩散&#xff0c;扩散完整个数组耗时就取决于两…

主流新能源汽车防盗模式简介

主流新能源汽车中&#xff0c;守卫模式是指车辆在停车状态下&#xff0c;通过特定的硬件和软件系统来保护车辆的安全&#xff0c;防止车辆被盗或被破坏。不同品牌的新能源汽车中&#xff0c;守卫模式的名称和功能略有不同&#xff0c;以下是常见的几种守卫模式及其对标&#xf…