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

news2025/7/15 20:07:09

打卡第22天,平衡二叉树,难,难,难。

今日任务

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

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

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]

在这里插入图片描述
在这里插入图片描述

我的题解

昨天的普通二叉树找最近公共祖先,直接搬过来了。

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        // 递归出口
        if(root == NULL) return NULL;
        if(root == p || root == q) return root;

        TreeNode* leftNode = lowestCommonAncestor(root->left, p, q);  // 左
        TreeNode* rightNode = lowestCommonAncestor(root->right, p, q); //右

        // 中
        if(leftNode != NULL && rightNode != NULL) return root; //左右节点返回均不为空,说明root是p、q最近公共祖先
        if(leftNode != NULL && rightNode == NULL) return leftNode; //左节点不为空,说明左子树出现q或者q
        if(leftNode == NULL && rightNode != NULL) return rightNode; //右节点不为空,说明右子树出现q或者q
        return NULL; // 均为空,说明左右子树均不出现p、q
    }
};

代码随想录

在这里插入图片描述

递归法

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root == NULL) return NULL;
        
        // 当p、q结点的值都 小于 此时结点的值,说明最近的公共祖先结点在左子树
        if(root->val > p->val && root->val > q->val) {
            TreeNode* leftNode = lowestCommonAncestor(root->left, p, q);
            if(leftNode) return leftNode;
        } 
        // 当p、q结点的值都 大于 此时结点的值,说明最近的公共祖先结点在右子树
        if(root->val < p->val && root->val < q->val) {
            TreeNode* rightNode = lowestCommonAncestor(root->right, p, q);
            if(rightNode) return rightNode;
        }
         // 当p、q结点的值 不全都小于,也不全都大于 此时结点的值,说明p、q结点分别在此时结点的左右子树两侧,那么最近的公共祖先结点就是此时的结点
        return root;
    }
};

迭代法


class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        while(root) {
        	// 当p、q结点的值都 小于 此时结点的值,说明最近的公共祖先结点在左子树
            if(root->val < p->val && root->val < q->val) root = root->right;
            // 当p、q结点的值都 大于 此时结点的值,说明最近的公共祖先结点在右子树
            else if(root->val > p->val && root->val > q->val) root = root->left;
            // 当p、q结点的值 不全都小于,也不全都大于 此时结点的值,说明p、q结点分别在此时结点的左右子树两侧,那么最近的公共祖先结点就是此时的结点
            else break;
        }
        return root;
    }
};

在这里插入图片描述

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

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

在这里插入图片描述
在这里插入图片描述

代码随想录

按照二叉搜索树的规则去遍历,遇到空节点就插入节点就可以了

迭代方法

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        TreeNode *node = new TreeNode(val);
   
        if(root == NULL) return node;

        TreeNode *cur = root;
        TreeNode* parent = root; //记录前一个结点

        while(cur != NULL) {
            parent = cur;
            if(val < cur->val) cur = cur->left;
            else cur = cur->right;
        }
		// 当遇到结点为空,插入我们的val结点
        if(val > parent->val) {
            parent->right = node;
        }
        else {
            parent->left = node;
        }
        
        return root;
    }
};

递归法

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if(root == NULL) {
            TreeNode *node = new TreeNode(val);
            return node;
        }
        if(val < root->val) root->left = insertIntoBST(root->left, val);
        if(val > root->val) root->right = insertIntoBST(root->right, val);
        return root;
    }
};

递归函数不用返回值也可以,找到插入的节点位置,直接让其父节点指向插入节点,结束递归,也是可以的。

 class Solution {
private:
    TreeNode* parent;
    void traversal(TreeNode* cur, int val) {
        if (cur == NULL) {
            TreeNode* node = new TreeNode(val);
            if (val > parent->val) parent->right = node;
            else parent->left = node;
            return;
        }
        parent = cur;
        if (cur->val > val) traversal(cur->left, val);
        if (cur->val < val) traversal(cur->right, val);
        return;
    }

public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        parent = new TreeNode(0);
        if (root == NULL) {
            root = new TreeNode(val);
        }
        traversal(root, val);
        return root;
    }
};

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

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

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

在这里插入图片描述
在这里插入图片描述

代码随想录

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        // 第一种情况:没找到删除的节点,遍历到空节点直接返回 NULL
        if(root == NULL) return NULL;
        if(root->val == key) {
            // 第二种情况:找到要删除的节点,而且他的左右节点都为空,直接返回 NULL
            if(root->left == NULL && root->right == NULL) {
                delete root; //释放内存
                return NULL;
            } 
            // 第三种情况:找到删除的节点,而且它的右节点为空,直接返回左孩子
            else if(root->left != NULL && root->right == NULL) {
                auto retNote = root->left;
                delete root; 
                return retNote;
            }
            // 第四种情况:找到删除的节点,而且它的左节点为空,直接返回右孩子 
            else if(root->left == NULL && root->right != NULL) {
                auto retNote = root->right;
                delete root; 
                return retNote;
            }
            // 第五种情况:找到删除的节点,但是它的左右节点为空
            // 找到该节点的右子树的最左节点,把该节点的左子树放在最左节点的左孩子
            // 返回该节点的右孩子
            else {
                TreeNode* cur = root->right;
                while(cur->left != NULL) cur = cur->left;
                cur->left = root->left;
                
                auto retNote = root; 
                root = root->right;  //返回旧root的右孩子作为新root
                delete retNote;  //释放内存
                return root;
            }
        }

        if(root->val > key) root->left = deleteNode(root->left, key); 
        if(root->val < key) root->right = deleteNode(root->right, key);
        return root;
    }
};

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

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

相关文章

BeanFactory接口

目录 概述 接口方法 BeanFactory重要的子类 概述 BeanFactory是容器的顶层接口,也是spring最核心的容器,管理bean的核心方法都在BeanFactory接口中定义。像ApplicationContext接口,ConfigurableApplicationContext接口都间接继承BeanFactory接口,既ApplicationContext调用ge…

Wwise集成到unreal

1、Wwise集成到Unreal 1.1 安装必要的软件 安装unreal 5.1&#xff1b;安装Audiokinetic Launcher&#xff1b;集成版本是Wwise 2021.1.12.7973。Audiokinetic Launcher下载地址&#xff1a; https://www.audiokinetic.com/zh/thank-you/launcher/windows/?refdownload&pl…

Go语言学习的第三天--下部分(Gin框架的基础了解)

每天都会分享Go的知识&#xff0c;喜欢的朋友关注一下。每天的学习分成两部分基础&#xff08;必要的&#xff0c;基础不牢地动山摇&#xff09;&#xff0c;另一部分是Go的一些框架知识&#xff08;会不定时发布&#xff0c;因为小Wei也是一名搬砖人&#xff09;。但是可以保证…

哪个牌子的蓝牙耳机最好?质量最好的蓝牙耳机排行榜

随着蓝牙耳机的发展越来越快速&#xff0c;蓝牙耳机市场涌现出五花八门的产品&#xff0c;外观不同、性能不一。最近看到很多人问&#xff0c;哪个牌子的蓝牙耳机最好&#xff1f;接下来&#xff0c;我来给大家推荐几款质量最好的蓝牙耳机排行榜&#xff0c;一起来看看吧。 一…

电商使用CRM系统有什么好处,如何选择

数据显示&#xff0c;使用电商CRM客户管理系统后&#xff0c;企业销售额提高了87%&#xff0c;客户满意度提高了74%&#xff0c;业务效率提高了73%。要在竞争激烈的电商市场取得成功&#xff0c;与目标受众的有效沟通是有效的方法。下面说说什么是电商CRM系统&#xff1f;电商C…

如何使用ArcGIS生成剖面图(附练习数据)

1、概述地形剖面图指沿地表某一直线方向上的垂直剖面图&#xff0c;以显示剖面线上断面地势起伏状况。能够制作剖面图的软件有很多&#xff0c;作为GIS行业的老大&#xff0c;ArcGIS当然也是可以的&#xff0c;这里给大家详细介绍一下ArcGIS中制作剖面图的知识&#xff0c;希望…

2.详解DEBUG模式

文章目录DEBUG模式解决了两个问题四种开启DEBUG的方式第一种第二种第三种第四种DEBUG的PIN码可以在浏览器端调试代码使用&#xff08;不推荐使用&#xff0c;了解就可以&#xff09;DEBUG模式解决了两个问题 flask代码中如果出现了异常&#xff0c;我们在浏览器中不会提示具体…

图床搭建,使用typora上传

1. 准备gitee作为图床的仓库 新建仓库 准备仓库的私人令牌&#xff0c;后面配合使用 点击个人设置——》私人令牌 注意私人令牌&#xff0c;复制保存好&#xff0c;后面不能再看了 2. 准备PicGO&#xff0c;并进行相关配置 PicGo官方下载链接 下载安装好node.js,下载网址 安…

【银行测试】必看的四类题型:这可是最经典的一套题目了

目录&#xff1a;导读 一、根据题目要求写出具体LINUX操作命令 二、JMETER题目 三、根据题目要求写出具体SQL语句 四、测试案例设计题 金三银四面试面对大厂面试官提问&#xff0c;如何回答&#xff1a;花3天背完这100道软件测试面试题&#xff01;银行测试的offer还不是手…

【GO】K8s 管理系统项目34[Linux环境–应用部署]

K8s 管理系统项目[Linux环境–应用部署] 1. 启动数据库 1.1 配置yum仓库 rm -f /etc/yum.repos.d/*.repo wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/…

Vue 实现图片监听鼠标滑轮滚动实现图片缩小放大功能

前言 其实想要实现功能很简单&#xff0c;就是在一张图片上监听鼠标滑轮滚动的事件&#xff0c;然后根据上滚还是下滚实现图片的缩放。 效果&#xff1a; 注&#xff1a;该配图使用《漫画|有趣的了解一下赋值、深浅拷贝》文章图片&#xff0c;不存在侵权问题。 实现思路 在…

规划数据指标体系方法(下)——新海盗模型

前面已经跟大家分享了规划数据指标体系的两种方法—— OSM 和 UJM 模型&#xff0c;分别从目标-策略以及用户旅途的角度阐述了规划数据指标体系的过程。今天我来跟大家分享最后一种规划数据指标体系的方法——新海盗模型。 了解新海盗模型 海盗模型&#xff0c;即 AARRR 模型&…

脑机接口科普0014——大脑

本文禁止转载&#xff01;&#xff01;&#xff01;&#xff01; 在提到脑机接口的时候&#xff0c;不得不提到大脑。 在我们的思维意识中&#xff0c;植物是没有大脑的。这是正确的。 在我们的思维意识中&#xff0c;动物都是有大脑的。 但是很明显&#xff0c;动物都有大…

程序员看过都说好的资源网站,你值得拥有。

程序员必备的相关资源网站一.技术社区1.GitHub2.Gitee&#xff08;码云&#xff09;3.稀土掘金4.OSCHINA开源中国5.CSDN6.博客园7.SegmentFault&#xff08;思否&#xff09;8.Stack Overflow9.Golang中文社区10.ChinaUnix11.51CTO12.Ruby China二.技术教程1.Devdocs2.码农教程…

案例解读| 从集中告警平台发展趋势看城商行如何落地数字化转型(二)

上期我们以具体案例入手&#xff0c;分享了集中告警平台到底应该与集中监控平台解耦还是紧绑定等问题。这一期依旧从具体案例切入&#xff0c;跟大家一起探索下告警与服务台的对接过程&#xff0c;以及这个过程中可能产生的问题。上期内容&#xff0c;一键回顾不迷路→案例解读…

17万字 JUC 看这一篇就够了(二) (精华)

今天我们继续来学习并发编程 17万字 JUC 看这一篇就够了(一) (精华) 线程池 基本概述 线程池&#xff1a;一个容纳多个线程的容器&#xff0c;容器中的线程可以重复使用&#xff0c;省去了频繁创建和销毁线程对象的操作 线程池作用&#xff1a; 降低资源消耗&#xff0c;减…

网络工程师面试题(面试必看)(1)

作者简介:一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 一.正题 1.TCP UDP协议的区别

YARN基本架构

主要由ResourceManager、NodeManager、ApplicationMaster和Container等组件构成&#xff0c;如图所YA示。 ResourceManager&#xff08;RM&#xff09; RM是全局资源管理器&#xff0c;负责整个系统的资源管理和分配 主要由两个组件构成&#xff1a;Scheduler调度器和应用程序…

ZYNQ嵌入式学习(5)

UARTUART简介发送FIFO接收FIFO模式切换寄存器操作中断和状态寄存器发送数据轮询中断接收数据轮询中断实验&#xff1a;串口中断数据环回UART简介 不需要了解时序。 UART是全双工异步收发的&#xff0c;没有时钟。 UART的操作通过配置和模式寄存器控制。 UART由独立的接受和发送…

Vue计算属性Computed

30. Vue计算属性Computed 1. 定义 Computed属性是Vue中的一个计算属性&#xff0c;是一种基于其它属性值计算而来的属性值&#xff0c;具有缓存机制&#xff0c;在依赖的属性值发生变化时会重新计算。 使用computed属性可以避免在模板中书写过多的计算逻辑&#xff0c;提高代…