代码随想录算法训练营三期 day 22 - 二叉树(8)

news2025/1/12 19:41:15

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

原文链接:235. 二叉搜索树的最近公共祖先
题目链接:235. 二叉搜索树的最近公共祖先
有序树 里:
从上向下递归遍历,第一次遇到 c u r cur cur 结点的数值在 p , q p, q p,q 结点对应数值的闭区间中,那么 c u r cur cur 就是 p p p q q q 的最近公共祖先。
请添加图片描述

递归

(1) 确定递归函数参数及返回值:
参数:当前结点 c u r cur cur 以及 p p p q q q
返回值:最近公共祖先 T r e e N o d e ∗ TreeNode* TreeNode;

    TreeNode* lowestCommonAncestor(TreeNode* cur, TreeNode* p, TreeNode* q) {

(2) 确定终止条件:

        if (cur == NULL) {
            return cur;
        }

(3) 确定单层递归逻辑:
如果 p → v a l < c u r → v a l   & &   q → v a l < c u r → v a l p \rightarrow val < cur \rightarrow val \ \&\&\ q \rightarrow val < cur \rightarrow val pval<curval && qval<curval, 说明目标区间在左子树上,向左遍历。
如果 p → v a l > c u r → v a l   & &   q → v a l > c u r → v a l p \rightarrow val > cur \rightarrow val \ \&\&\ q \rightarrow val > cur \rightarrow val pval>curval && qval>curval, 说明目标区间在右子树上,向右遍历。
由于 本题只需要搜索到一条符合条件的边 ,所以遇到递归函数的返回值不为空直接返回即可。
剩下的情况,就是 c u r cur cur 结点的数值在 p , q p, q p,q 结点对应数值的闭区间中,那么 c u r cur cur 就是 p p p q q q 的最近公共祖先,返回 c u r cur cur 即可。

        if (p -> val < cur -> val && q -> val < cur -> val) {
            TreeNode* left = lowestCommonAncestor(cur -> left, p, q);
            if (left != NULL) {
                return left;
            }
        }
        if (p -> val > cur -> val && q -> val > cur -> val) {
            TreeNode* right = lowestCommonAncestor(cur -> right, p, q);
            if (right != NULL) {
                return right;
            }
        } 
        return cur;

代码如下:

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* cur, TreeNode* p, TreeNode* q) {
        if (cur == NULL) {
            return cur;
        }
        if (p -> val < cur -> val && q -> val < cur -> val) {
            TreeNode* left = lowestCommonAncestor(cur -> left, p, q);
            if (left != NULL) {
                return left;
            }
        }
        if (p -> val > cur -> val && q -> val > cur -> val) {
            TreeNode* right = lowestCommonAncestor(cur -> right, p, q);
            if (right != NULL) {
                return right;
            }
        } 
        return cur;
    }
};

迭代

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* cur, TreeNode* p, TreeNode* q) {
        while (cur) {
            if (p -> val < cur -> val && q -> val < cur -> val) {
                cur = cur -> left;
            } else if (p -> val > cur -> val && q -> val > cur -> val) {
                cur = cur -> right;
            } else {
                return cur;
            }
        }
        return NULL;
    }
};

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

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

递归法

(1) 确定递归函数参数及返回值:
参数就是根节点指针,以及要插入元素。
递归函数的返回类型为 T r e e N o d e ∗ TreeNode * TreeNode, 可以利用返回值完成新加入的结点与其父结点的赋值操作。

    TreeNode* insertIntoBST(TreeNode* root, int val) {

(2) 确定终止条件:
终止条件就是遍历的结点为 N U L L NULL NULL 的时候,就是要插入结点的位置了,并把插入的结点返回。

        if (root == NULL) {
            TreeNode* node = new TreeNode(val);
            return node;
        }

这里把添加的结点返回给上一层,就完成了父子结点的赋值操作了。
(2) 确定单层递归逻辑:
搜索树是有序树,可以根据插入元素的数值,决定递归方向,
下一层将加入结点返回,本层用 r o o t → l e f t root \rightarrow left rootleft 或者 r o o t → r i g h t root \rightarrow right rootright 将其接住。

        if (val < root -> val) {
            root -> left = insertIntoBST(root -> left, val);
        }
        if (val > root -> val) {
            root -> right = insertIntoBST(root -> right, val);
        }
        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 {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if (root == NULL) {
            TreeNode* node = new TreeNode(val);
            return node;
        }
        TreeNode* cur = root;
        TreeNode* parent = root;
        while (cur != NULL) {
            parent = cur;
            if (val < cur -> val) {
                cur = cur -> left;
            } else if (val > cur -> val) {
                cur = cur -> right;
            }
        }
        TreeNode* node = new TreeNode(val);
        if (val < parent -> val) {
            parent -> left = node;
        } else if (val > parent -> val) {
            parent -> right = node;
        }
        return root;
    }
};

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

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

递归

(1) 确定递归函数参数及返回值:
可以借助递归函数返回值来删除结点。

TreeNode* deleteNode(TreeNode* root, int key) {

(2) 确定终止条件:
没找到要删除的结点,遍历到空直接返回:

        // 1. 没找到删除的结点,遍历到空结点直接返回了
        if (root == NULL) {
            return root;
        }

(3) 确定单层递归逻辑:
有以下五种情况:
(1) 没找到删除的结点,遍历到空结点直接返回了;
(2) 找到删除的结点:
i. 左右孩子都为空(叶子结点),直接删除结点, 返回 N U L L NULL NULL 为根结点;
ii. 删除结点的左孩子为空,右孩子不为空,删除结点,右孩子补位,返回右孩子为根结点;
iii. 删除结点的右孩子为空,左孩子不为空,删除结点,左孩子补位,返回左孩子为根结点;
iv. 左右孩子结点都不为空,则将删除结点的左子树头结点(左孩子)放到删除结点的右子树的最左面结点的左孩子上,返回删除结点右孩子为新的根结点,如下图:
请添加图片描述

         // 1. 没找到删除的结点,遍历到空结点直接返回了
        if (root == NULL) {
            return root;
        }
        // 2. 找到删除的结点
        if (key == root -> val) {
            // (1) 左右孩子都为空,直接删除结点,返回空结点
            if (root -> left == NULL && root -> right == NULL) {
                delete root;
                return NULL;
            } 
            // (2) 左孩子为空,右孩子不为空,返回右孩子
            else if (root -> left == NULL) {
                TreeNode* tmp = root -> right;
                delete root;
                return tmp;
            } 
            // (3) 左孩子不为空,右孩子为空,返回左孩子
            else if (root -> right == NULL) {
                TreeNode* tmp = root -> left;
                delete root;
                return tmp;
            } 
            // (4) 左右孩子都不为空
            else {
                // 找右子树最左边的结点
                TreeNode* cur = root -> right;
                while (cur -> left != NULL) {
                    cur = cur -> left;
                }
                // 把要删除的结点 (root) 的左子树放在 cur 的左孩子位置
                cur -> left = root -> left;
                TreeNode* tmp = root;
                root = root -> right;
                delete tmp;
                return root;
            }
        }

这里相当于把新的结点返回给上一层,上一层就要用 r o o t → l e f t root \rightarrow left rootleft 或者 r o o t → r i g h t root \rightarrow right rootright 接住,代码如下:

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

总体代码如下:

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        // 1. 没找到删除的结点,遍历到空结点直接返回了
        if (root == NULL) {
            return root;
        }
        // 2. 找到删除的结点
        if (key == root -> val) {
            // (1) 左右孩子都为空,直接删除结点,返回空结点
            if (root -> left == NULL && root -> right == NULL) {
                delete root;
                return NULL;
            } 
            // (2) 左孩子为空,右孩子不为空,返回右孩子
            else if (root -> left == NULL) {
                TreeNode* tmp = root -> right;
                delete root;
                return tmp;
            } 
            // (3) 左孩子不为空,右孩子为空,返回左孩子
            else if (root -> right == NULL) {
                TreeNode* tmp = root -> left;
                delete root;
                return tmp;
            } 
            // (4) 左右孩子都不为空
            else {
                // 找右子树最左边的结点
                TreeNode* cur = root -> right;
                while (cur -> left != NULL) {
                    cur = cur -> left;
                }
                // 把要删除的结点 (root) 的左子树放在 cur 的左孩子位置
                cur -> left = root -> left;
                TreeNode* tmp = root;
                root = root -> right;
                delete tmp;
                return root;
            }
        }
        if (key < root -> val) {
            root -> left = deleteNode(root -> left, key);
        }
        if (key > root -> val) {
            root -> right = deleteNode(root -> right, key);
        }
        return root;
    }
};

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

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

相关文章

内网渗透神器CobaltStrike之Beacon详解(三)

Beacon的种类 HTTP Beacon和HTTPS Beacon 这两个beacon的原理是通过发送http请求与受害主机通信来传达命令, 以此实现控制效果 优点是传输数据快, 缺点时隐蔽性差, 容易被防火墙或内网审计工具拦截 TCP Beacon 自CS4.0版本之后只有反向的TCP Beacon可用, 基于TCP协议的通信…

取证初级案例操作大纲

文章目录**取证初级案例操作大纲**1) 证据文件中有没有存在被删除的Doc文档&#xff1f;如果有的话&#xff0c;请导出并记录文件名及路径&#xff1a;2) 证据文件中有没有存在被删除的图片&#xff1f;如果有的话&#xff0c;请记录文件名及路径&#xff1a;3) 证据文件中哪几…

object类的一些方法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 Object类 输出对象地址 object类里的tostring方法&#xff1a; 正确输出对象里内容 判断俩个对象大小&#xff1a; object类里的equlas方法&#xff1a; 自己实现一…

SpringCloud - 微服务理论基础

文章目录1.微服务架构1.1 什么是微服务1.2 Spring Cloud 简介1.3 Spring Cloud 技术栈2.Boot 和 Cloud 版本选型3.Cloud 服务升级1.微服务架构 1.1 什么是微服务 微服务架构是一种架构模式&#xff0c;它提倡单一应用程序划分成一组小的服务&#xff0c;服务直接相互协调、相互…

Python PyInstaller 打包成 Win、Mac 应用程序(app / exe)

一、简介 python 提供了几个用来打包的模块&#xff0c;主要有 py2app、py2exe、pyinstaller。附&#xff1a;pyinstaller、py2app、py2exe、fbs 对比与爬坑。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-whT6cPog-1668880648443)(https://p1-jue…

(续)SSM整合之springmvc笔记(RESTful之HiddenHttpMethodFilter源码解析)(P147)了解

RESTful之HiddenHttpMethodFilter源码解析 由于浏览器只支持发送get和post方式的请求&#xff0c;那么该如何发送put和delete请求呢&#xff1f; SpringMVC 提供了 HiddenHttpMethodFilter 帮助我们将POST 请求转换为DELETE 或PUT 请求 HiddenHttpMethodFilter 处理put和delete…

java计算机毕业设计ssm陕理工图书馆管理系统

项目介绍 随着互联网技术的发发展,计算机技术广泛应用在人们的生活中,逐渐成为日常工作、生活不可或缺的工具,高校各种管理系统层出不穷。高校作为学习知识和技术的高等学府,信息技术更加的成熟,为高校图书馆借阅开发必要的系统,能够有效的提升管理效率。一直以来,高校图书馆一…

Docker搭建Redis集群

Docker搭建Redis集群 注意&#xff1a;Redis搭建集群最少需要6个Redis节点&#xff0c;其中3个作为主节点&#xff0c;3个作为从节点&#xff1b; 为了方便&#xff0c;这里用Docker在一台机器上启动6个容器来作为集群&#xff0c;生产上建议用多台服务器搭建&#xff1b; 创建…

4.1.3 名称的特殊处理

名称的特殊处理 类成员变量的名称处理&#xff1a; 对于类的数据成员&#xff0c;其的名称经过编译器的处理会在程序员定义名称的后面再加上class的名称&#xff0c;进而形成独一无二的命名&#xff0c;例如下面的的成员变量x再经过类处理后有可能为x_7Point3d。 class Point…

Linux之手把手教你捋清楚make和makefile

文章目录背景简单介绍make和makefile依赖关系和依赖方法项目清理以及伪目标背景 以往的C语言编程&#xff0c;我们一般都在一些像VS2019这样的集成开发环境(IDE)下编写&#xff0c;一个工程中的源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0…

Spring框架的概述及基本应用

Spring的基本应用 文章目录Spring的基本应用1. Spring 概述1.1 什么是Spring1.2 Spring 框架的优点1.3 Spring的体系结构2. Spring的核心容器2.1 BeanFactory2.2 ApplicationContext3. Spring的入门程序3.1 在pom下利用maven导入Spring所需要的jar包3.2 简单搭建起demo结构3.3 …

Java中数组的定义与使用(Java系列3)

目录 前言&#xff1a; 1.什么是数组 2.数组的创建 3.数组的初始化 4.数组的使用 5.数组是引用类型 6.基本类型变量与引用类型变量的区别 7.数组的应用 8.二维数组 结束语&#xff1a; 前言&#xff1a; 前面小编与大家分享了C语言与Java中的区别&#xff0c;还有一…

leaflet教程041: Point 和 LatLng 坐标互相转换

第041个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中使用Point和LatLng,这里做了两者之间的转换。 注意 两者转换后的值,返回相对于原点像素的相应像素坐标或经纬度坐标。zoom改变,原点(地图图层左上角的投影像素坐标)的值会改变,所以获得的值也会变化。…

51单片机学习笔记1 简介及开发环境

51单片机学习笔记1 简介及开发环境一、51单片机1. STC89C52单片机简介2. 命名规则3. 封装&#xff08;1&#xff09;PDIP&#xff08;2&#xff09;LQFP&#xff08;3&#xff09;PLCC&#xff08;4&#xff09;PQFP二、STC8051结构1. STC 8051 内部结构图2. 内部结构框图3. 单…

Android设置TabLayout熟悉及下划线宽度

Tablayout的使用 属性 app&#xff1a;tabMod 设置Tab模式 app&#xff1a;tabTextColor 设置文本颜色 app&#xff1a;tabSelectedTextColor 设置选中文本颜色 app:tabIndicatorColor 设置下滑条颜色 app:tabMaxWidth“xxdp” 设置最大的tab宽度 app:tabMinWidth“xxdp” 设置…

牛客网之SQL100题(7)-字符串截取、切割、删除、替换

知识点&#xff1a; &#xff08;1&#xff09;substring_indexsubstring_index(str,delim,count) str:要处理的字符串 delim:分隔符 count:计数 &#xff08;2&#xff09;切割、截取、删除、替换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 select -- 替换法 replace(string, 被…

类型转换C11

类型转换 C类型转换分为显式类型转换和隐式类型转换 &#xff0c;隐式类型转换由编译器自动完成&#xff0c;这里只讨论显式类型转换。 旧式风格的类型转换 type(expr); // 函数形式的强制类型转换 (type)expr; // C语言风格的强制类型转换现代C风格的类型转换 cast-name&l…

1-2 VMware安装Rocky9.0和Ubuntu22.04系统

文章目录前言下载链接VMware使用安装Rocky9.0系统Rocky初始化安装Ubuntu22.04系统Ubuntu初始化VMware快照前言 VMware虚拟机软件是一个“虚拟PC”软件&#xff0c;它使你可以在一台机器上同时运行二个或更多Windows、DOS、LINUX系统。 Rocky Linux 9.0 操作系统与2022年7月14…

基于matlab GUI的数字图像处理系统

目 录 摘 要 I Abstract II 第1章 绪论 1 1.1选题背景及意义 1 1.2国内外研究现状 2 1.2.1国内研究现状 2 1.2.2国外研究现状 3 1.3研究主要内容 3 第2章 数字图像处理系统设计 5 2.1设计概括 5 2.2文件 6 2.2.1打开 6 2.2.2保存 6 2.2.3退出 6 2.3图像变形 7 2.3.1图像缩放 7 …

Spring Cloud Gateway 使用示例

Spring Cloud Gateway 使用示例 作者&#xff1a; Grey 原文地址&#xff1a; 博客园&#xff1a;Spring Cloud Gateway 使用示例 CSDN&#xff1a;Spring Cloud Gateway 使用示例 说明 Spring Cloud Gateway 用于构建 API 网关&#xff0c;基于 Spring WebFlux。 在Spr…