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

news2024/11/16 15:55:43

目录

  • 一、LeetCode 235. 二叉搜索树的最近公共祖先
    • 思路:
    • C++代码
  • 二、LeetCode 701.二叉搜索树中的插入操作
    • 思路
    • C++代码
  • 三、LeetCode 450.删除二叉搜索树中的节点
    • 思路
    • C++代码
  • 总结


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

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

文章讲解:代码随想录
视频讲解:自底向上查找,有点难度! | LeetCode:236. 二叉树的最近公共祖先

思路:

 判断两个结点在二叉树中的最近公共祖先,笔者的算法思路为设置全局变量ances记录最近的公共祖先结点,设计递归函数searchOffspring自底向上地遍历结点,递归函数返回bool值来判断子树中是否含有pq

 递归函数主体中,判断当前结点是否是最近祖先有两种情况:

  1. 当前结点的左右子树分别出现过pq
  2. 当前结点为pq中的一个,另一个在当前结点的子树中

递归终止条件为遍历到空节点,此时返回false;

C++代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* ances; //全局变量记录最近祖先结点
    bool searchOffspring(TreeNode* node, TreeNode* p, TreeNode* q){
        //使用bool值记录当前结点的子树是否出现过p或q
        if(!node) return false;
        bool left = searchOffspring(node->left, p, q);
        bool right = searchOffspring(node->right, p, q);
        if(node == p || node == q){ //若当前结点和p、q相同
            if(left || right){
                ances = node;
                return false; //防止最近祖先上方结点重复赋值
            }
            return true;
        }
        else if(left && right){ //当前结点的左右子树出现过p、q,则为最近祖先。
            ances = node;
            return false;
        }
        return left || right;
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        searchOffspring(root, p, q);
        return ances;
    }
};

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

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

文章讲解:代码随想录
视频讲解:原来这么简单? | LeetCode:701.二叉搜索树中的插入操作

思路

 给二叉搜索树中插入新元素,由于题目没有要求二叉搜索树平衡的条件,那么只需要按照二叉搜索的方式递归遍历,直到遍历到第一个空的孩子结点,把插入的新元素放到这个孩子结点的位置即可。
在这里插入图片描述

C++代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        TreeNode* subroot = root;
        while(subroot){
            if(val < subroot->val){
                if(subroot->left){
                    subroot = subroot->left;
                    continue;
                }
                else{
                    TreeNode* node = new TreeNode(val);
                    subroot->left = node;
                    return root;
                }
            }
            else{
                if(subroot->right){
                    subroot = subroot->right;
                    continue;
                }
                else{
                    TreeNode* node = new TreeNode(val);
                    subroot->right = node;
                    return root;
                }
            }

        }
        TreeNode* node = new TreeNode(val);
        return node;
    }
};

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

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

文章讲解:代码随想录
视频讲解:调整二叉树的结构最难!| LeetCode:450.删除二叉搜索树中的节点

思路

 本题也需要实现二叉搜索树的一个基本维护操作,但与插入操作不同的是,删除结点一般都是非叶子结点,意味着不能只单纯实现删除一个结点操作,还需要调整删除结点后,该结点左右孩子的结构,并连接到原来的二叉树上。

 我们以二叉搜索树中一个含有左右孩子的一般结点为例。

 首先,删除结点后,该结点的左右孩子结构如何调整?我们注意到,结点的左子树是包含所有小于该结点的数,右子树包含所有大于该结点的树,那么左子树的所有元素一定比右子树的最小元素小,借助这个特性,我们可以使用如下策略调整结构,即:
把左子树的根结点,连接到右子树的最左下方结点(右子树中的最小值)的左孩子位置。

 调整好结构以后,需要考虑连接到原二叉树的问题。由于删除结点无论是他的双亲的左孩子还是右孩子,该结点的子树和该结点的双亲大小关系一定是确定的,所以修改好结构的子树,只需要把子树根结点(上一段右孩子的根节点)连接到双亲即可。

 需要考虑几种特殊情况,当删除结点只有一个孩子结点时,直接连接该孩子结点即可,无需进行结构调整;当删除结点是叶子结点时,只删除结点即可。

C++代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if(!root) return root;

        TreeNode* node; //记录需要删除的结点
        TreeNode* subroot = root; //记录删除结点的双亲,便于调整结构

        if(key == root->val){
            if(!root->left){
                return root->right;
            }
            if(!root->right){
                return root->left;
            }
            node = root;
        }
        else{
            node = (key < root->val) ? root->left: root->right;
            while(node){//查找结点
                if(key < node->val){
                    subroot = node;
                    node = node->left;
                } 
                else if(key > node->val){
                    subroot = node;
                    node = node->right;
                } 
                else break;
            }
        }

        if(node){ //删除结点
            TreeNode* inst;
            if(node->right){
                inst = node->right;
                while(inst->left){ 
                //把删除结点的左子树,放在删除结点右子树的最左边叶子位置
                    inst = inst->left;           
                }
                inst->left = node->left;
                inst = node->right;
            } 
            else{
                inst = node->left;
            }          
            if(node->val < subroot->val) subroot->left = inst;
            else subroot->right = inst;
            if(node == root) root = inst;
        }
        return root;
    }
};

总结

 对于二叉搜索树中的删除结点操作应加强复习。


文章图片来源:代码随想录 (https://programmercarl.com/)

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

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

相关文章

C语言:for、while、do-while循环语句

目录 前言 一、while循环 1.1 while语句的执行流程 1.2 while循环的实践 1.3 while循环中的break和continue 1.3.1 break 1.3.2 continue 二、for循环 2.1 语法形式 2.2 for循环的执行流程 2.3 for循环的实践 2.4 for循环中的break和continue 2.4.1 break 2.4.2 …

Java数组03:数组边界、数组的使用

本节内容视频链接&#xff1a;https://www.bilibili.com/video/BV12J41137hu?p55&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5https://www.bilibili.com/video/BV12J41137hu?p55&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 1.数组边界 数组下标的合法区间[ 0, Len…

综合监管云平台存在信息泄露漏洞_中科智远综合监管云平台

0x01阅读须知 本文章仅供参考&#xff0c;此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考。本文章仅用于信息安全防御技术分享&#xff0c;因用于其他用途而产生不良后果,作者不承担任何法律责任&#…

昇腾 - 快速理解AscendCL(Ascend Computing Language)基础概念的HelloWord

昇腾 - 快速理解AscendCL&#xff08;Ascend Computing Language&#xff09;基础概念的HelloWord flyfish AscendCL&#xff08;Ascend Computing Language&#xff09;是一套用于在昇腾平台上开发深度神经网络应用的C语言API库&#xff0c;提供运行资源管理、内存管理、模型…

鸿蒙(API 12 Beta3版)【录像流二次处理(C/C++)】媒体相机开发指导

通过ImageReceiver创建录像输出&#xff0c;获取录像流实时数据&#xff0c;以供后续进行图像二次处理&#xff0c;比如应用可以对其添加滤镜算法等。 开发步骤 导入NDK接口&#xff0c;接口中提供了相机相关的属性和方法&#xff0c;导入方法如下。 // 导入NDK接口头文件#in…

ArcGIS Pro基础:软件的常用设置:中文语言、自动保存、默认底图

上图所示&#xff0c;在【选项】&#xff08;Options&#xff09;里找到【语言】设置&#xff0c;将语言切换为中文选项&#xff0c;记得在安装软件时&#xff0c;需要提前安装好ArcGIS语言包。 上图所示&#xff0c;在【选项】里找到【编辑】设置&#xff0c;可以更改软件默认…

Java面试八股之如何保证消息队列中消息不重复消费

如何保证消息队列中消息不重复消费 要保证消息队列中的消息不被重复消费&#xff0c;通常需要从以下几个方面来着手&#xff1a; 消息确认机制&#xff1a; 对于像RabbitMQ这样的消息队列系统&#xff0c;可以使用手动确认&#xff08;manual acknowledge&#xff09;机制来…

Eureka原理与实践:构建高效的微服务架构

Eureka原理与实践&#xff1a;构建高效的微服务架构 Eureka的核心原理Eureka Server&#xff1a;服务注册中心Eureka Client&#xff1a;服务提供者与服务消费者 Eureka的实践应用集成Eureka到Spring Cloud项目中创建Eureka Server创建Eureka Client&#xff08;服务提供者&…

ISA95 企业控制集成标准

ANSI/ISA-95 企业控制系统集成介绍及其全系列最新标准下载&#xff08;转&#xff09;https://www.cnblogs.com/TonyJia/p/17616347.html ANSI 1. 综述 ISA-95 简称S95&#xff0c;也有称作SP95。ISA-95 是企业系统与控制系统集成国际标准&#xff0c;由国际自动化学会(ISA…

react最好用的swiper插件和拖动插件 react-tiny-slider react-draggable

react移动端项目&#xff0c;其实有挺多的ui框架的&#xff0c;但是我们公司的项目&#xff0c;都是自己封装的ui库&#xff0c;又不可能为了一个轮播图就去再安装一个ui库 所以找了很多的轮播插件&#xff0c;都是不能满足需求 最后找到了它&#xff0c;react-tiny-slider&…

1 什么是linux驱动

1 目录 1 一、什么是linux驱动&#xff1f; 1、驱动的作用 2、 3、驱动的分类 4、linux源码 5、最简单的linux驱动 二、如何编译驱动程序 -- 有两种编译方法&#xff1a; -- 什么是Linux内核模块&#xff1f; -- Linux内核模块的编译 一、什么是linux驱动&#xff…

原生HTML5、CSS、JavaScript实现简易网易云音乐播放

1.效果图 2.源码 1.index.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>网易云音乐</title><link rel"stylesheet" href"../CSS/index.css"> </head>…

C++:新枚举与新结构

一、枚举 &#xff08;一&#xff09;C枚举&#xff1f;真整数&#xff01; 考虑下面的程序 #include <stdio.h> #include <stdlib.h>typedef enum {spring, summer, autumn, winter} Season;void printSeason(Season season){switch(season){case spring:print…

【Java学习】实现图书管理系统

所属专栏&#xff1a;Java学习 &#x1f341;1. 功能演示 用户分为普通用户和管理员&#xff0c;登录进系统之后可以对图书进行一系列操作&#xff0c;此时我们要明白&#xff0c;对图书的操作是通过书架来执行的&#xff0c;我们平常在图书馆上借书就是在书架上 &#x1f…

简简单单用用perf

实践前提&#xff1a;正确安装 perf 和 FlameGrap。若没安装&#xff0c;心领神会亦可。 1 示例程序 #define m_loop() ({ for(int i0; i < 1000000; i); })void fb(void) {m_loop(); }void fj(void) {fb(); }void fy(void) {m_loop(); }void loop(void) {for (;;) {fy();…

实习教训,永远铭记

1.毕了业宁宁可收入低一点&#xff0c;但一定去那种开发产品有规章制度&#xff0c;有流程规范的公司。 永远不接受小公司&#xff0c;没有任何规范可言的小公司&#xff01;&#xff01;&#xff01;&#xff01; 永远不接受小公司&#xff0c;没有任何规范可言的小公司&…

Docker手动在虚拟机上部署前端、后端和数据库

&#x1f4a5; 该系列属于【SpringBoot基础】专栏&#xff0c;如您需查看其他SpringBoot相关文章&#xff0c;请您点击左边的连接 目录 一、项目准备 二、MySQL数据库部署 三、SpringBoot后端部署 四、Vue前端部署 一、项目准备 准备数据库、前端项目、后端项目。 准备一…

YOLOv8跑通POSE分类--姿态检测coco8-pos数据集

目录 1.数据集格式如下 2.训练的代码如下 3.训练的网络如下 4.训练的结果如下 简单留个备注&#xff0c;方便自己以后查找 1.数据集格式如下 txt里面的格式 类别 中心点x,y 宽高 姿态1的x,姿态1的y,姿态可见度。。。。 <class-index> <x> <y> <widt…

使用dockerDesktop下载x86,amd64,arm64镜像

开启梯子 修改dockerDesktop配置&#xff0c;将experimental的值设置成 true&#xff0c;意思是&#xff1a;开启manifest实验特性 重启docker后下载镜像 –platform后面就是架构版本&#xff0c;x86,amd64,arm64 C:\Users\dell> docker pull --platformarm64 nginx:late…

Linux--C语言之指针

文章目录 一、指针的引入二、指针概述三、指针变量&#xff08;一&#xff09;指针变量的定义语法&#xff1a;举例&#xff1a;注意&#xff1a; &#xff08;二&#xff09;指针变量的使用1. 指针变量的赋值2. 操作指针变量的值3. 操作指针变量指向的值4. 两个有关运算符的使…