算法打卡day19|二叉树篇08|Leetcode 235. 二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点

算法题

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

题目链接:235. 二叉搜索树的最近公共祖先

大佬视频讲解:二叉搜索树的最近公共祖先视频讲解

个人思路

昨天做过一道二叉树的最近公共祖先,而这道是二叉搜索树,那就要好好利用这个有序的特点来解决这道题,因为是有序树,所以如果 中间节点是 q 和 p 的公共祖先,那么 中节点的数组 一定是在 [p, q]区间的。即 中节点 > p && 中节点 < q 或者 中节点 > q && 中节点 < p。

解法
递归法

那么只要从上到下去遍历,遇到 cur节点是数值在[p, q]区间中则一定可以说明该节点cur就是p 和 q的公共祖先。但一定是最近公共祖先吗?画个图看看

如图下,从根节点搜索,第一次遇到 cur节点是数值在[q, p]区间中,即 节点7,此时可以说明 q 和 p 一定分别存在于 节点 7的左子树,和右子树中。

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

这道题和二叉树的搜索还有一点不同,就是本题就是标准的搜索一条边的写法,遇到递归函数的返回值,如果不为空,立刻返回

再加上这道题没有递归顺序,因为这里没有中节点的处理逻辑;递归函数就很简单了如下

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode 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;//返回参数}
}

时间复杂度:O(n);(遍历整棵树)

空间复杂度:O(n);(递归树的高度,如果是一个高度不平衡的树(例如链状结构)高度与n接近)

迭代法

和递归法思路相似,改成了while循环,找到最近公共祖先就返回节点;

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;}
}

时间复杂度:O(n);(遍历整棵树)

空间复杂度:O(1);(只有一个节点)


Leetcode 701.二叉搜索树中的插入操作

题目链接:701.二叉搜索树中的插入操作

大佬视频讲解:二叉搜索树中的插入操作视频讲解

个人思路

因为说还可以重构二叉树,一时间不知道怎么下手

解法
递归法

可以不考虑题目中提示所说的改变树的结构的插入方式,只考虑如何插入节点,只要按照二叉搜索树的规则去遍历,遇到空节点就插入节点就可以了。

递归三步走:

1.确定递归函数参数以及返回值

参数就是根节点指针,以及要插入元素,

递归函数需要有返回值,可以利用返回值完成新加入的节点与其父节点的赋值操作

递归函数的返回类型为节点类型TreeNode *

2.确定终止条件

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

3.确定单层递归的逻辑

搜索树是有方向了,可以根据插入元素的数值,决定递归方向。

class Solution {public TreeNode insertIntoBST(TreeNode root, int val) {// 如果当前节点为空,也就意味着val找到了合适的位置,此时创建节点直接返回。if (root == null) { return new TreeNode(val);}if (root.val < val){root.right = insertIntoBST(root.right, val); // 递归创建右子树}else if (root.val > val){root.left = insertIntoBST(root.left, val); // 递归创建左子树}return root;}
}

时间复杂度:O(n);(最差遍历一遍树)

空间复杂度:O(n);(递归树的高度,如果是一个高度不平衡的树(例如链状结构)高度与n接近)

迭代法

迭代的方法就需要记录当前遍历节点的父节点了,这个和没有返回值的递归函数实现的代码逻辑是一样的。

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;} }//当root为空时,就找到了插入节点的位置,再根据值的大小选择插入左边还是右边if (pre.val > val) {pre.left = new TreeNode(val);} else {pre.right = new TreeNode(val);}return newRoot;}
}

时间复杂度:O(n);(遍历整棵树)

空间复杂度:O(1);(因为是原地修改树的方式进行插入,不涉及递归调用栈的空间增长;除了返回的新节点外,算法不需要额外的空间来存储任何信息)


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

题目链接:450.删除二叉搜索树中的节点

大佬视频讲解:删除二叉搜索树中的节点视频讲解

个人思路

思路不清晰,主要是如何在删除节点后有多少种情况要解决不太明白

解法
递归法

因为二叉搜索树添加节点只需要在叶子上添加就可以的,不涉及到结构的调整,而删除节点操作涉及到结构的调整。这里使用递归函数的返回值来完成把节点从二叉树中移除的操作。

递归三步走:

1.确定递归函数参数以及返回值

上道题是通过递归返回值来加入新节点, 这里也可以通过递归返回值删除节点

2.确定终止条件

遇到空返回,其实这也说明没找到删除的节点,遍历到空节点直接返回了

3.确定单层递归的逻辑

二叉搜索树中删除节点遇到的情况有以下五种情况

  • 第一种情况:没找到删除的节点,遍历到空节点直接返回了
  • 找到删除的节点
    • 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
    • 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
    • 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
    • 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。

其中第五种情况比较难理解,画图理解,如下。

class Solution {public TreeNode deleteNode(TreeNode root, int key) {if (root == null) return root;//终止条件if (root.val == key) {//找到删除节点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 = root.right;return root;}}if (root.val > key) root.left = deleteNode(root.left, key);//遍历左树if (root.val < key) root.right = deleteNode(root.right, key);return root;}
}

时间复杂度:O(n);(遍历二叉树)

空间复杂度:O(n);(递归树的高度,如果是一个高度不平衡的树(例如链状结构)高度与n接近)

 迭代法

用迭代法模拟递归法中的逻辑来删除节点,但需要一个pre记录cur的父节点方便做删除操作

class Solution {public TreeNode deleteNode(TreeNode root, int key) {if (root == null){return null;}//寻找对应的对应的前面的节点,以及他的前一个节点TreeNode cur = root;TreeNode pre = null;//父节点while (cur != null){if (cur.val < key){pre = cur;cur = cur.right;} else if (cur.val > key) {pre = cur;cur = cur.left;}else {break;}}if (pre == null){return deleteOneNode(cur);}if (pre.left !=null && pre.left.val == key){pre.left = deleteOneNode(cur);}if (pre.right !=null && pre.right.val == key){pre.right = deleteOneNode(cur);}return root;}public TreeNode deleteOneNode(TreeNode node){//处理删除节点的情况if (node == null){return null;}if (node.right == null){return node.left;}TreeNode cur = node.right;while (cur.left !=null){cur = cur.left;}cur.left = node.left;return node.right;}}

时间复杂度:O(n);(遍历二叉树)

空间复杂度:O(1);(因为是原地修改树的方式进行插入,不涉及递归调用栈的空间增长;除了返回的新节点外,算法不需要额外的空间来存储任何信息)


以上是个人的思考反思与总结,若只想根据系列题刷,参考卡哥的网址代码随想录算法官网

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

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

相关文章

Linux: 调用接口

进程相关 获取进程id与创建进程 头文件: <unistd.h>getpid() : 获取进程idgetppid() : 获取父进程的idfork() : 创建子进程, 给父进程返回子进程的id, 给子进程返回0 等待子进程 头文件: <sys/types.h> <sys/wait.h>pid_t wait(int*status); 返回值: 成…

欧拉openeuler23.09默认软件源太慢了,修改为华为云更新源,附上具体配置内容。

因为是直接在原有的文件基础上修改的&#xff0c;所以有一些不需要的内容我用#号屏蔽掉了。 #generic-repos is licensed under the Mulan PSL v2. #You can use this software according to the terms and conditions of the Mulan PS L v2. #You may obtain a copy of Mulan…

2000-2021年各省外商直接投资水平面板数据(含原始数据+计算结果)(无缺失)

2000-2021年各省外商直接投资水平面板数据&#xff08;含原始数据计算结果&#xff09;&#xff08;无缺失&#xff09; 1、时间&#xff1a;2000-2021年 2、指标&#xff1a;外商直接投资额&#xff08;万美元&#xff09;、外商直接投资额&#xff08;万元&#xff09;、国…

代码随想录 二叉树—二叉树的最大深度

思路&#xff1a;depth初始为0&#xff0c;要是有子孩子就depth加1&#xff0c;循环过了之后最后一个没子孩子&#xff0c;depth也会加1&#xff0c;弥补了先开始的0。简单题&#xff0c;模板略微改一点。 题解c&#xff1a; /*** Definition for a binary tree node.* struc…

lv17 安防监控实现之通信协议制定 2

项目功能框架分层 ***************************************************** 分层分析&#xff1a; ***************************************************** web网页端显示部分&#xff1a; 环境信息摄像头采集图像&#xff1a; 硬件控制&#xff1a; A9数据处理部分 A9-Z…

Linux下最常用的MySQL运维脚本

MySQL是一个广泛用于Web应用程序和服务器的开源关系型数据库管理系统。在Linux环境中&#xff0c;运维MySQL数据库可能涉及到许多日常任务&#xff0c;如备份、性能优化、监控等。为了提高效率&#xff0c;许多运维工作可以通过编写脚本来自动化执行。本文将介绍一些在Linux下最…

Leetcode64. 最小路径和

Problem: 64. 最小路径和 文章目录 思路解题方法复杂度Code 思路 动态规划,偷房子问题变形 解题方法 dp[i][j] min(dp[i-1][j],dp[i][j-1])grid[i][j]; 复杂度 时间复杂度: O ( m ∗ n ) O(m*n) O(m∗n) 空间复杂度: O ( m ∗ n ) O(m*n) O(m∗n) Code class Solution { pub…

leetcode代码记录(动态规划基础题(斐波那契数列)

目录 1. 题目&#xff1a;2. 斐波那契数列&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a…

[LeetCode][LCR173]点名——二分结合输入数据特点找边界

题目 LCR 173. 点名 某班级 n 位同学的学号为 0 ~ n-1。点名结果记录于升序数组 records。假定仅有一位同学缺席&#xff0c;请返回他的学号。 示例 1&#xff1a; 输入&#xff1a;records [0,1,2,3,5] 输出&#xff1a;4 示例 2&#xff1a; 输入&#xff1a;records [0, …

王道c语言-判断对称数,sprintf应用

Description 输入一个整型数&#xff0c;判断是否是对称数&#xff0c;如果是&#xff0c;输出yes&#xff0c;否则输出no&#xff0c;不用考虑这个整型数过大&#xff0c;int类型存不下&#xff0c;不用考虑负值 方法一 取余乘位权 #include <stdio.h> int main() {i…

TensorFlow的介绍和简单案例

TensorFlow是一个开源的机器学习框架,由Google开发和维护。它旨在使构建和训练机器学习模型变得更加容易,同时提供高度灵活性和可扩展性。 TensorFlow基于数据流图的概念。数据流图是一个由节点和边组成的有向图,其中节点表示操作,边表示数据的流动。TensorFlow通过在数据…

YOLOv9更换iou|包含CIoU、DIoU、MDPIoU、GIoU

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;助力高效涨点&#xff01;&#xff01;&#xff01; 一、改进点介绍 更换YOLOv9中使用的Iou计算方式&#xff0c;目前支持CIoU、DIoU、MDPIoU、GIoU。 二、Iou模块详解 2.1 模块简介 Iou的主要思想&…

<JavaEE> 数据链路层 -- 以太网协议、MTU限制、ARP协议

目录 以太网协议 什么是以太网&#xff1f; 以太网的帧格式 什么是MAC地址&#xff1f; MAC地址和IP地址的对比&#xff1f; MTU&#xff08;最大传输单元&#xff09;限制 什么是MTU限制&#xff1f; MTU对IP协议有什么影响&#xff1f; MTU对UDP协议有什么影响&…

HDOJ 2034

人见人爱A-B Problem Description 参加过上个月月赛的同学一定还记得其中的一个最简单的题目&#xff0c;就是{A}{B}&#xff0c;那个题目求的是两个集合的并集&#xff0c;今天我们这个A-B求的是两个集合的差&#xff0c;就是做集合的减法运算。&#xff08;当然&#xff0c;…

pre_min[0:10, 2:3] = pre和pre_min[0:10, 2] = pre区别

在NumPy中&#xff0c;数组切片的语法非常具体&#xff0c;它决定了哪些元素被选取或赋值。对于您提到的两个切片表达式&#xff0c;pre_min[0:10, 2:3] 和 pre_min[0:10, 2]&#xff0c;它们有本质的区别&#xff0c;主要体现在所选的维度和形状上。 pre_min[0:10, 2:3]:这个…

微服务:Bot代码执行

每次要多传一个bot_id 判网关的时候判127.0.0.1所以最好改localhost 创建SpringCloud的子项目 BotRunningSystem 在BotRunningSystem项目中添加依赖&#xff1a; joor-java-8 可动态编译Java代码 2. 修改前端&#xff0c;传入对Bot的选择操作 package com.kob.botrunningsy…

【SpringBoot3】整合Druid数据源和Mybatis 项目打包和运行

文章目录 一、整合Druid数据源二、整合Mybatis2.1 MyBatis整合步骤2.1 Mybatis整合实践2.1 声明式事务整合配置2.1 AOP整合配置 三、项目打包和运行命令启动和参数说明 总结web 与 springboot 打包区别JDK8的编译环境 执行17高版本jar 一、整合Druid数据源 创建模块 &#xff1…

云备份项目2

云备份项目 文章目录 云备份项目4. 服务端代码设计4.1 服务端工具类实现4.1.1 文件实用工具类设计4.1.2 Json实用工具类设计 4.2 服务端配置信息模块实现4.2.1 系统配置信息4.2.2 单例文件配置类设计 4.3 服务端数据管理模块实现4.3.1 备份数据类的实现4.3.2 数据管理类的设计 …

Js输入输出语句

输入语法 prompt("您想输入的是&#xff1f;")输出语法: 语法1: document.write(‘要出的内容’&#xff09; <body><script>document.write("你好")document.write("<h1>我是<h1>")</script> </body>作…

Yaml格式解析

文章目录 YAML格式介绍YAML格式解析 YAML格式介绍 YAML&#xff08;YAML Ain’t Markup Language&#xff09;是一种常用于配置文件的人类可读的数据序列化标准。它通常用于存储和传输数据&#xff0c;并且由于其简洁性、可读性和易于编写的特性&#xff0c;它经常被用于编写配…