算法训练营 day22 二叉树 二叉搜索树的最近公共祖先 二叉搜索树中的插入操作 删除二叉搜索树中的节点

news2024/9/20 16:40:50

算法训练营 day22 二叉树 二叉搜索树的最近公共祖先 二叉搜索树中的插入操作 删除二叉搜索树中的节点

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

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

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

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

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

递归法

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

    参数就是当前节点,以及两个结点 p、q。

    返回值是要返回最近公共祖先,所以是TreeNode 。

  • 确定终止条件

    遇到空返回就可以了

  • 确定单层递归的逻辑

    在遍历二叉搜索树的时候就是寻找区间[p.val, q.val](注意这里是左闭又闭)

    那么如果 cur.val 大于 p.val,同时 cur.val 大于q.val,那么就应该向左遍历(说明目标区间在左子树上)。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) return null;
        if (root.val > p.val && root.val > q.val) {
            TreeNode left = lowestCommonAncestor(root.left, p, q);
            if (left!=null) return left;
        }
        if (root.val < p.val && root.val < q.val) {
           TreeNode right = lowestCommonAncestor(root.right, p, q);
           if (right!=null) return right;
        }
        return root;
    }
}

//精简
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;
    }
}

迭代法

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

二叉搜索树中的插入操作

701. 二叉搜索树中的插入操作 - 力扣(LeetCode)

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

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

如下演示视频中可以看出:只要按照二叉搜索树的规则去遍历,遇到空节点就插入节点就可以了。

在这里插入图片描述

递归法

class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if (root == null) // 如果当前节点为空,也就意味着val找到了合适的位置,此时创建节点直接返回。
            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;
    }
}

迭代法

class Solution {
    public static TreeNode insertIntoBST(TreeNode root, int val) {
        if (root == null) return new TreeNode(val);
        TreeNode result = root;
        TreeNode pre=null;

        while (root != null) {
            pre = root;//保存前一个节点
            if (root.val < val) root = root.right;
            else if (root.val > val) root = root.left;
        }
        if (root==null){
            if (pre.val > val) {
                pre.left = new TreeNode(val);
            } else {
                pre.right = new TreeNode(val);
            }
        }
        return result;
    }
}

删除二叉搜索树中的节点

450. 删除二叉搜索树中的节点 - 力扣(LeetCode)

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

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

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

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

有以下五种情况:

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

在这里插入图片描述

递归法

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        //第一种情况没有找到目标值
        if (root==null) return null;
        if (root.val==key){
            //第二种情况目标值为叶子节点
            if (root.left==null&&root.right==null){
                return null;
            }
            //第三种情况目标值左为空 右不为空
            else if (root.left!=null&&root.right==null){
                return root.left;
            }
            //第四种情况目标值右为空 左不为空
            else if (root.right!=null&&root.right==null){
                return root.right;
            }
            //第五种情况目标值左右都不为空
            else {
                TreeNode cur = root.right;
                while (cur.left!=null) cur = cur.left;
                cur.left = root.left;
                return root.right;
            }
        }
        if (root.val>key) root.left = deleteNode(root.left,key); 
        if (root.val<key) root.right = deleteNode(root.right,key);
        
        return root;
    }
}

迭代法

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) break;
            pre = cur;
            if (cur.val > key) cur = cur.left;
            else if (cur.val < key) cur = cur.right;
        }
        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;
    }

    private TreeNode deleteOneNode(TreeNode root) {
            //第二种情况目标值为叶子节点
            if (root.left==null&&root.right==null){
                return null;
            }
            //第三种情况目标值左为空 右不为空
            else if (root.left!=null&&root.right==null){
                return root.left;
            }
            //第四种情况目标值右为空 左不为空
            else if (root.right!=null&&root.right==null){
                return root.right;
            }
            //第五种情况目标值左右都不为空
            else {
                TreeNode cur = root.right;
                while (cur.left!=null) cur = cur.left;
                cur.left = root.left;
                return root.right;
            }
	}
}

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

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

相关文章

第三章 逻辑与推理

命题逻辑谓词逻辑知识图谱推理因果推理 3.1 命题逻辑 逻辑和推理是基于知识的操作。 命题逻辑是应用一套形式化规则对以符号表示的描述性陈述进行推理的系统。在命题逻辑中&#xff0c;一个或真或假的描述性陈述被称为原子命题&#xff0c;对原子命题的内部结构不做任何解析。…

UnityC#的lock用法简记

UnityC#的lock用法简记简述代码实例一、单线程二、多线程无lock三、多线程使用lock死锁注意拓展lock->InvokeMonitor参考链接简述 多线程环境中&#xff0c;不使用lock锁&#xff0c;会形成竞争条件&#xff0c;导致错误。 使用lock锁可以保证当有线程操作某个共享资源时&a…

【ONE·C || 操作符详解】

总言 C语言&#xff1a;各种操作符的使用介绍。 文章目录总言1、算术操作符2、移位操作符2.1、整体介绍2.2、左移操作符2.3、右移操作符&#xff08;逻辑右移、算术右移&#xff09;3、位操作符3.1、整体介绍3.2、演示实例3.2.1、按位与3.2.2、按位或3.2.3、按位异或3.2.4、按位…

离线文章画像计算--Tfidf计算

2.4.2 Tfidf计算 2.4.2.1 目的 计算出每篇文章的词语的TFIDF结果用于抽取画像 2.4.2.2TFIDF模型的训练步骤 读取N篇文章数据文章数据进行分词处理TFIDF模型训练保存&#xff0c;spark使用count与idf进行计算利用模型计算N篇文章数据的TFIDF值 2.4.2.3 实现 想要用TFIDF进行…

【数据结构初阶(Java)】认识时间复杂度和空间复杂度

目录 前言&#xff1a; 1、算法效率 2、时间复杂度 1、大O的渐近表示法&#xff08;不是一个准确的&#xff09; 2、时间复杂度练习题&#xff08;没有明确要求&#xff0c;计算的时间复杂度就是最坏情况下&#xff09; 3、空间复杂度 前言&#xff1a; 如何衡量一个算法的…

Java中多线程wait和notify的用法

目录 一、wait和notify/notifyAll的由来 二、wait()方法 三、notify方法 3.1 notify的作用 3.2 wait和notify的 相互转换代码图 3.3 notifyAll 四、为什么需要notify和wait都需要上锁&#xff1f; 五、wait和sleep的对比 前言&#xff1a;由于线程之间是抢占式执行的&a…

Linux常用命令——tftp命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) tftp 在本机和tftp服务器之间使用TFTP协议传输文件 补充说明 tftp命令用在本机和tftp服务器之间使用TFTP协议传输文件。 TFTP是用来下载远程文件的最简单网络协议&#xff0c;它其于UDP协议而实现。嵌入式linu…

RTMP协议封装H264和H265协议详解

RTMP协议封装H264和H265协议详解 文章目录RTMP协议封装H264和H265协议详解1 RTMP和FLV2 RTMP协议封装H264视频流2.1 RTMP发送AVC sequence header2.2 RTMP发送AVCC视频帧数据‘3 RTMP协议封装H265视频流1 RTMP和FLV 有关RTMP和FLV格式详细介绍可查看如下文章&#xff1a; http…

2022 Moonbeam的点点滴滴离不开社区支持

Moonbeam成为首个上线波卡的平行链已经有一周年&#x1f382;啦&#xff0c;这是一段疯狂的旅程&#x1f3cd;。 为了纪念这一时刻&#xff0c;我们通过公开数据来回顾这一年的众多里程碑、更新和整体发生的一切。 让我们来回顾一下Moonbeam在2022年取得了哪些成就吧。 &…

GIS二维电子地图开发总结

二维平面地图&#xff0c;目前支撑设备渲染&#xff0c;真实场景&#xff0c;后期电子围栏&#xff0c;运动轨迹等业务需求做铺垫 一、所涉及的技术栈&#xff1a; 1.Openlayers,加载渲染地图 2.Geoserver 发布wms和wfs&#xff08;&#xff09;服务 3.Arcgis,Arcmap,进行源文件…

3.1、Ubuntu20桌面版远程连接SSHMobaXterm远程连接编辑器

连接SSH 安装系统完成并登陆后&#xff0c;输入 修改源码地址 进入apt文件夹 cd /etc/apt 备份文件 cp sources.list sources.list.bak 修改源码地址 vi sources.list # See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to # newer versions of…

数据结构初级<排序>

本文已收录至《数据结构(C/C语言)》专栏&#xff01; 作者&#xff1a;ARMCSKGT 你的阅读和理解将是我极大的动力&#xff01; 目录 前言 排序的概念 常见排序简述 正文 直接插入排序 原理 代码实现 分析 希尔排序 原理 代码实现 分析 直接选择排序 原理 代码…

类加载的时机与过程

------ 摘自 周志明 《深入理解Java虚拟机》类加载的时机一个类型从被加载到虚拟机内存中开始&#xff0c;到卸载出内存为止&#xff0c;它的整个生命周期将会经历加载&#xff08;Loading&#xff09;、验证&#xff08;Verification&#xff09;、准备&#xff08;Preparati…

6、数组的常见运算

目录 一、数组的算术运算 二、数组的关系运算 三、数组的逻辑运算 一、数组的算术运算 &#xff08;1&#xff09;数组的加减运算&#xff1a;通过格式AB或A-B可实现数组的加减运算。但是运算规则要求数组A和B的维数相同。 示例1&#xff1a; A[1 2 3 4]B[2 4 6 8]C[1 1 …

三种简洁易行的方法解决基于Vue.js的组件通信

在总结Vue组件化编程的数据通信方面&#xff0c;看了网上的很多资料&#xff0c;都是讲父子组件的数据交互也就是参数传递&#xff0c;在组件的通信方面分几种情况&#xff0c;比如父子组件、非父子的兄弟组件、非父子的其他组件等等&#xff0c;这样看来&#xff0c;基于Vue.j…

STC15系列单片机EEPROM读写示例

STC15系列单片机EEPROM读写示例&#x1f33c;STC15手册有关EEPROM描述 &#x1f33e;STC15系列单片机内部集成了大容量的EEPROM&#xff0c;其与程序空间是分开的。利用ISP/IAP技术可将内部DataFlash当EEPROM&#xff0c;擦写次数在10万次以上。EEPROM可分为若干个扇区&#xf…

Android 蓝牙开发——蓝牙协议配置(七)

蓝牙主要分为两种模式&#xff0c;一种是媒体输出&#xff08;Source&#xff09;端&#xff0c;一种是媒体输入&#xff08;Sink&#xff09;端。也可以理解为服务端&#xff08;Server&#xff09;与客户端&#xff08;Client&#xff09;的关系。 蓝牙配置文件&#xff08;B…

4-1指令系统-指令格式

文章目录一.指令的基本格式1.结构2.长度3.根据操作数地址码数目分类&#xff08;1&#xff09;零地址指令&#xff08;2&#xff09;一地址指令&#xff08;3&#xff09;二地址指令&#xff08;4&#xff09;三地址指令&#xff08;5&#xff09;四地址指令二.扩展操作码指令格…

Maven学习(二):Maven基础概念

Maven基础概念一、仓库二、坐标三、全局setting与用户setting区别一、仓库 仓库&#xff1a;用于存储资源&#xff0c;包含各种jar包&#xff1b;仓库分类&#xff1a; 本地仓库&#xff1a;自己电脑上的存储仓库&#xff0c;连接远程仓库获取资源&#xff1b;远程仓库&#x…

信息论复习—离散信道及其容量

目录 信道的简介&#xff1a; 信道的分类&#xff1a; 离散无记忆信道&#xff08;DMC&#xff09;模型&#xff1a; 转移概率&#xff1a; 离散无记忆信道的转移矩阵 输出仅与当前的输入有关&#xff1a; 后验概率&#xff1a; 离散无记忆信道的后验概率矩阵 &#xf…