算法打卡day19

今日任务:

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

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

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

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

题目链接:235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)

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

示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3 解释: 节点 5 和节点 1 的最近公共祖先是节点 3。

示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5 解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。

说明:
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉树中。

文章讲解:代码随想录 (programmercarl.com)

视频讲解:二叉搜索树找祖先就有点不一样了!| 235. 二叉搜索树的最近公共祖先哔哩哔哩bilibili

思路:

这题与昨天打卡的236.二叉树的最近公共祖先这题比较像

在236题中提到

如果某节点node为p,q的最近公共祖先,那么p,q会出现以下三种情况:

1.p 和 q 在 node 的子树中,且分列 node 的异侧(即分别在左、右子树中);
2.p=node,且 q 在 node 的左或右子树中;
3.q=node,且 p 在 node 的左或右子树中;

在236题中是普通二叉树,没有顺序,所以我们需要按顺序遍历节点找到p,q

在今天这题中,我们可以利用搜索二叉树的特点

  • 节点的左子树只包含小于当前节点的数。
  • 节点的右子树只包含大于当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

所以我们通过比较p,q,与当前节点的大小即可快速找p,q

class TreeNode:def __init__(self, x):self.val = xself.left = Noneself.right = Noneclass Solution:def lowestCommonAncestor2(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':# 如果p,q同在左侧,则继续往左子树找if root.val > p.val and root.val > q.val:return self.lowestCommonAncestor(root.left, p, q)# 如果p,q同在右侧,则继续往右子树找elif root.val < p.val and root.val < q.val:return self.lowestCommonAncestor(root.right, p, q)# q,p在异侧,则返回当前节点;或者root为空,返回空(返回root也就是返回空)else:return root

这题也可以使用迭代法,因为搜索二叉树有序,不存在回溯

class Solution:def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':if not root:return rootwhile root:if root.val > p.val and root.val > q.val:root = root.leftelif root.val < p.val and root.val < q.val:root = root.rightelse:return root# 改进def lowestCommonAncestor2(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':while root:if root.val > p.val and root.val > q.val:root = root.leftelif root.val < p.val and root.val < q.val:root = root.rightelse:breakreturn root

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

题目链接:701. 二叉搜索树中的插入操作 - 力扣(LeetCode)

给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据保证,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。

文章讲解:代码随想录 (programmercarl.com)

视频讲解:原来这么简单? | LeetCode:701.二叉搜索树中的插入操作哔哩哔哩bilibili

思路:

我们不考虑题目中提示所说的改变树的结构的插入方式,插入值一定可以找到合适的叶子节点位置

实现过程:

1)只要按照二叉搜索树的规则去遍历,当遇到空节点时,也就是我们要插入的位置,我们返回插入点即可。此时还不知道是左节点还是右节点。

2)判断插入值和当前节点的大小,如果小于当前节点,则表明应该是当前节点的左孩子接受返回值

3)如果大于当前节点,则表明应该是当前节点的右孩子接受返回值

4)最后返回root即可(如果根节点本身为空,则出现我们第一步,返回插入点)

class Solution2:def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:# 当遇到空节点时,则将插入值变为节点if not root:root = TreeNode(val)return root# 如果当前节点大于插入节点值,则将插入值赋给当前节点的左孩子if root.val > val:root.left = self.insertIntoBST(root.left, val)# 如果当前节点小于插入节点值,则将插入值赋给当前节点的右孩子if root.val < val:root.right = self.insertIntoBST(root.right, val)return root

也可以用迭代法,思路与之前一样,这里我是在判断过程中就赋予了值,成功插入即返回结果。

class Solution3:def insertIntoBST(self, root, val):if root is None:  # 如果根节点为空,创建新节点作为根节点并返回node = TreeNode(val)return node# 如果节点不为空,一直遍历直到找到空节点node = root  # 最后要返回根节点,为了不改变root,重新定一个变量while node:if node.val > val:if node.left is None:node.left = TreeNode(val)break  # 找到则跳出循环else:node = node.leftelse:if node.right is None:node.right = TreeNode(val)breakelse:node = node.rightreturn root

代码随想录提供的代码是采用两个指针记录的当前节点与父节点,当前节点为空时,则找到插入点,比较父节点与插入值大小,将父节点指向插入值即可,详细代码见代码随想录

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

题目链接:450. 删除二叉搜索树中的节点 - 力扣(LeetCode)

文章讲解:代码随想录 (programmercarl.com)

视频讲解:调整二叉树的结构最难!| LeetCode:450.删除二叉搜索树中的节点哔哩哔哩bilibili

思路:

这题比较有意思,不像插入节点,直接插入到叶子节点,这题删除一个节点,可能会导致树的结构变化

二叉搜索树中删除节点遇到的情况都搞清楚。

有以下五种情况:

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

第四种情况比较复杂,删除节点左不空右不空,将右子树继位(也可以左子树继位)。我们需要将删除节点的左子树,给移到右子树上。根据搜索二叉树的特性,应该把左子树移到右子树左底层(只有左底层是略微大于删除节点的,左子树是略微小于删除节点,所以应该把左子树放到右子树的左底层)。然后再将上上节点指向当前节点

动画中的二叉搜索树中,删除元素7, 那么删除节点(元素7)的左孩子就是5,删除节点(元素7)的右子树的最左面节点是元素8。

将删除节点(元素7)的左孩子放到删除节点(元素7)的右子树的最左面节点(元素8)的左孩子上,就是把5为根节点的子树移到了8的左孩子的位置。

要删除的节点(元素7)的右孩子(元素9)为新的根节点。.

这样就完成删除元素7的逻辑,

class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = right
class Solution:def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:# 如果节点为空if not root:return root# 找到删除节点if root.val == key:# 情况一:删除节点左空右空(即跟节点),直接删除,返回空值if root.left is None and root.right is None:return None# 情况二:删除节点左空右不空,将右节点返回elif root.left is None:return root.right# 情况三:删除节点左不空右空,将左节点返回elif root.right is None:return root.left# 情况四:删除节点左不空右不空,将右子树继位(也可以左子树继位)# 将删除节点的左子树,给移到右子树上。根据搜索二叉树的特性,应该把左子树移到右子树左底层(只有左底层是略微大于删除节点的,左子树是略微小于删除节点,所以应该把左子树放到右子树的左底层)else:cur = root.rightwhile cur.left is not None:cur = cur.leftcur.left = root.leftreturn root.rightif root.val > key:root.left = self.deleteNode(root.left, key)if root.val < key:root.right = self.deleteNode(root.right, key)return root

感想:多做多做多做!

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

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

相关文章

45.跳跃游戏||

// 定义一个名为Solution的类 class Solution {// 定义一个public方法jump&#xff0c;输入参数为一个整数数组nums&#xff0c;返回值类型为整数public int jump(int[] nums) {// 初始化跳跃次数结果变量为0int result 0;// 初始化当前覆盖的最远距离下标为0int end 0;// 初…

【C语言】Infiniband驱动init_dev_assign函数

一、注释 一个内核模块的初始化函数&#xff0c;用于分配和初始化某些资源。以下是对代码块的逐行中文注释&#xff1a; // 定义一个初始化设备分配的函数 static void init_dev_assign(void) {int i 1;spin_lock_init(&dev_num_str_lock); // 初始化自旋锁if (mlx4_fil…

【MySQL】5.2MySQL高级语句与sql语句

模板 test、class、class0 mysql> select * from test; -------------------------------- | idcard | name | age | hobbid | -------------------------------- | 01 | lizi | 18 | guangjie | | 02 | monor | 22 | zhaijia | | 03 | sansan | …

前端-html-02

1.列表 标签名功能和语义属性单标签还是双标签ul无序列表包裹元素双标签 ol 有序列表包裹元素双标签li列表项双标签dl定义列表包裹元素双标签dt定义列表项标题双标签dd定义列表项描述双标签 li必须由Ul或者ol包裹 <!DOCTYPE html> <html><head><…

学透Spring Boot — 创建一个简单Web应用

从今天开始&#xff0c;我们将开始学习一个新的系列&#xff0c;那就是在项目中用得非常广泛的一个框架 —— Spring Boot&#xff0c;我们会循序渐进地介绍 Spring Boot 的方方面面&#xff0c;包括理论和实战&#xff0c;也会介绍和Spring Boot一些热点面试题。 概论 本文是…

2024年springboot+vue毕业设计选题推荐

2024年&#xff0c;随着技术的发展和市场需求的变化&#xff0c;基于Spring Boot和Vue的毕业设计选题可以更加注重新兴技术的融合和解决实际问题。以下是一些建议的选题方向&#xff1a; 1. 基于Spring Boot和Vue的智能健康管理系统 - 设计并实现一个集成了运动数据、睡眠监…

L2-3浪漫侧影

“侧影”就是从左侧或者右侧去观察物体所看到的内容。例如上图中男生的侧影是从他右侧看过去的样子&#xff0c;叫“右视图”&#xff1b;女生的侧影是从她左侧看过去的样子&#xff0c;叫“左视图”。 520 这个日子还在打比赛的你&#xff0c;也就抱着一棵二叉树左看看右看看…

免费使用Claude 3!这个平台集成了所有主流的AI聊天机器人!Poe AI 2024最新版教程

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

机器人是怎么计时的(通用定时器 - 时基单元)

目录 一&#xff0c;引言 二&#xff0c;机器人的“大脑” 三&#xff0c;时基单元介绍 1&#xff0c;定时器框图 2&#xff0c;时基单元 &#xff08;1&#xff09;预分频器 &#xff08;2&#xff09;CNT计数器 &#xff08;3&#xff09;自动重装载寄存器 四&#…

vue多语言包i18n

1.安装 如果是vue2直接安装8.2.1版本&#xff0c;否则会出现版本不匹配的错误 npm install vue-i18n8.2.1 --save2.文件编辑 在src目录下创建文件 en.js export const h {system: "Background management system",loginOut:"LoginOut",LayoutSet:Layout …

后端前行Vue之路(二):模版语法之插值与指令

1.概述 Vue.js的模板语法是一种将Vue实例的数据绑定到HTML文档的方法。Vue的模板语法是一种基于HTML的扩展&#xff0c;允许开发者将Vue实例中的数据绑定到HTML元素&#xff0c;以及在HTML中使用一些简单的逻辑和指令。Vue.js 基于 HTML 的模板语法允许开发者声明式地将 DOM 绑…

【pytest、playwright】多账号同时操作

目录 方案实现思路&#xff1a; 方案一&#xff1a; 方案二&#xff1a; 方案实现思路&#xff1a; 依照上图所见&#xff0c;就知道&#xff0c;一个账号是pytest-playwright默认的环境&#xff0c;一个是 账号登录的环境 方案一&#xff1a; 直接上代码&#xff1a; imp…