算法打卡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 = x
        self.left = None
        self.right = None

class 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 root
        while root:
            if root.val > p.val and root.val > q.val:
                root = root.left
            elif root.val < p.val and root.val < q.val:
                root = root.right
            else:
                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.left
            elif root.val < p.val and root.val < q.val:
                root = root.right
            else:
                break
        return 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.left
            else:
                if node.right is None:
                    node.right = TreeNode(val)
                    break
                else:
                    node = node.right

        return 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 = val
        self.left = left
        self.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.right
                while cur.left is not None:
                    cur = cur.left
                cur.left = root.left
                return root.right

        if root.val > key:
            root.left = self.deleteNode(root.left, key)
        if root.val < key:
            root.right = self.deleteNode(root.right, key)
        return root

感想:多做多做多做!

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

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

相关文章

Android 自定义EditText

文章目录 Android 自定义EditText概述源码可清空内容的EditText可显示密码的EditText 使用源码下载 Android 自定义EditText 概述 定义一款可清空内容的 ClearEditText 和可显示密码的 PasswordEditText&#xff0c;支持修改提示图标和大小、背景图片等。 源码 基类&#xf…

大语言模型(LLM)token解读

1. 什么是token&#xff1f; 人们经常在谈论大模型时候&#xff0c;经常会谈到模型很大&#xff0c;我们也常常会看到一种说法&#xff1a; 参数会让我们了解神经网络的结构有多复杂&#xff0c;而token的大小会让我们知道有多少数据用于训练参数。 什么是token&#xff1f;比…

【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…

量化交易入门(二十三)什么是MTM指标,原理是什么

MTM指标全称是Momentum指标,翻译为动量指标。它用来衡量市场价格在一定时间内上涨或下跌的幅度,属于趋势型指标。其计算公式是: MTM(N) 当前收盘价 - N日前的收盘价 其中N表示统计的周期数,常用参数有6日、12日和24日。 MTM指标的应用要点如下: 判断趋势强弱:MTM数值越大,表…

泛型的进阶

1 通配符 &#xff1f; 我们想调用fun函数帮我们打印&#xff0c;但由于不知道Message具体是什么类型&#xff0c;所以我们可以使用 &#xff1a; &#xff1f;即通配符 当我们将fun函数中改为Message<?>此时就不会报错 2 通配符的上界&#xff1a; <? extends 上…

如何使用 ArcGIS Pro 自动矢量化水系

对于某些要素颜色统一的地图&#xff0c;比如电子地图&#xff0c;可以通过图像识别技术将其自动矢量化&#xff0c;这里为大家介绍一下 ArcGIS Pro 自动矢量化水系的方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的电子地图数据&#…

二分练习题——123

123 二分等差数列求和前缀和数组 题目分析 连续一段的和我们想到了前缀和&#xff0c;但是这里的l和r的范围为1e12&#xff0c;明显不能用O(n)的时间复杂度去求前缀和。那么我们开始观察序列的特点&#xff0c;可以按照等差数列对序列进行分块。如上图&#xff0c;在求前10个…

虚拟机Linux(centos)安装python3.8(超详细)

一、Python下载 下载地址&#xff1a;https://www.python.org/downloads/source/ 输入下面网址即可直接下载&#xff1a; python3.8&#xff1a;https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tgz python3.6&#xff1a;https://www.python.org/ftp/python/3.6.5/…

Chrome 插件 tabs API 解析

Chrome.tabs API 解析 使用 chrome.tabs API 与浏览器的标签页系统进行交互&#xff0c;可以使用此 API 在浏览器中创建、修改和重新排列标签页 Tabs API 不仅提供操作和管理标签页的功能&#xff0c;还可以检测标签页的语言、截取屏幕截图&#xff0c;以及与标签页的内容脚本…

Prompt Engineering的4 种方法

此为观看视频 4 Methods of Prompt Engineering 后的笔记。 从通用模型到专用模型&#xff0c;fine tuning&#xff08;微调&#xff09;和prompt engineering&#xff08;提示工程&#xff09;是2种非常重要的方法。本文深入探讨了prompt engineering的4种方法。 首先&#…

MySQL数据库的高级SQL语句与高级操作(2)

目录 一、子查询 1、语法: 2、以下例子均以图中两个表为基础 例子1&#xff1a;查询yun1班级大于85分的学生记录 例子2&#xff1a;将yun2班的学生记录放在一个单独的表中&#xff0c;叫yun2 例子3&#xff1a;教务处误把yun3班叫张丽的学生的成绩搞错了&#xff0c;应该为…

Machine Learning机器学习之向量机(Support Vector Machine,SVM)

目录 前言 算法提出背景&#xff1a; 核心思想&#xff1a; 原理&#xff1a; 应用领域&#xff1a; 一、支持向量机分类&#xff08;主要变体&#xff09; 二、构建常见的支持向量机模型 基于Python 中的 Scikit-learn 库构建线性支持向量机&#xff08;SVM&#xff09; 三、向…

Matplotlib数据可视化实战-2绘制折线图(2)

2.11营业额可视化 已知某学校附近一个烧烤店2022年每个月的营业额如下图所示。编写程序绘制折线图对该烧烤店全年营业额进行可视化&#xff0c;使用红色点画线连接每个月的数据&#xff0c;并在每个月的数据处使用三角形进行标记。 烧烤店营业额 月份123456789101112营业额/万…

Python调用Python并传参

常规 在Python中调用另一个Python脚本可以通过多种方式实现&#xff0c;例如使用subprocess模块或者直接导入模块。以下是两种常见的方法&#xff1a; 使用subprocess模块&#xff1a; 调用 import subprocess # 调用另一个Python脚本&#xff0c;例如script.py subprocess.r…

ES5和ES6的深拷贝问题

深拷贝我们知道是引用值的一个问题&#xff0c;因为在拷贝的时候&#xff0c;拷贝的是在内存中同一个引用。所以当其中的一个应用值发生改变的时候&#xff0c;其他的同一个引用值也会发生变化。那么针对于这种情况&#xff0c;我们需要进行深度拷贝&#xff0c;这样就可以做到…

centos安装jdk的坑

文章目录 一、安装jdk二、查找jdk的目录三、配置JAVA_HOME 一、安装jdk 我们一般用yum search java | grep jdk查询可以安装的jdk 但是一定要注意如下图&#xff0c;必须知道jdk和jre的区别 yum install java-1.8.0-openjdk-devel.x86_64二、查找jdk的目录 用如下命令 sudo…

云电脑安全性怎么样?企业如何选择安全的云电脑

云电脑在保障企业数字资产安全方面&#xff0c;采取了一系列严谨而全面的措施。随着企业对于数字化转型的深入推进&#xff0c;数字资产的安全问题日益凸显&#xff0c;而云电脑作为一种新兴的办公模式&#xff0c;正是为解决这一问题而生。云电脑安全吗&#xff1f;可以放心使…

Mybatis-获取参数值的两种方式

1. ${ } 和 #{ } MyBatis获取参数值的两种方式&#xff1a;${ } 和 #{ } 对于初学者来说&#xff0c;理解MyBatis中获取参数值的两种方式——#{}和${}&#xff0c;关键在于明白它们如何影响SQL语句的构建以及为何在安全性、灵活性上有显著差异。下面我将用简单易懂的语言来解…

Flutter开发之下标

Flutter开发之下标 在iOS开发中使用下标就很方便&#xff0c;本文主要是记录一下Flutter中系统自带的下标&#xff0c;还可以通过对应的方法编写自己的下标。 在Objective-C中的下标 关键字Subscript。 NSArray - (ObjectType)objectAtIndexedSubscript:(NSUInteger)idx A…

Abaqus周期性边界代表体单元Random Sphere RVE 3D (Mesh)插件

插件介绍 Random Sphere RVE 3D (Mesh) - AbyssFish 插件可在Abaqus生成三维具备周期性边界条件(Periodic Boundary Conditions, PBC)的随机球体骨料及骨料-水泥界面过渡区(Interfacial Transition Zone, ITZ)模型。即采用周期性代表性体积单元法(Periodic Representative Vol…