Day 23 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树 总结篇

news2025/2/6 14:51:34

修剪二叉搜索树

给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。

669.修剪二叉搜索树

669.修剪二叉搜索树1

​ 最直接的想法,遍历树然后找到root->val在[L,R]以外的节点删除,通过递归处理返回根节点;

​ 如果此时简单的给出这种代码:

       root->left = trimBST(root->left, low, high);
       root->right = trimBST(root->right, low, high);

​ 就会忽视掉当前节点不在范围内但是节点左(右)子树可能在范围内的情况;

​ 如下图所示:

​ 也就是在删除节点时,还要对其子树进行判断;至于实现方式可以参考上一题的子树嫁接方法,无须重构二叉树结构;

​ 下面写递归三部曲:

​ 首先确定递归函数参数和返回值:遍历整棵树,做修改,其实不需要返回值也可以完成修剪(其实就是从二叉树中移除节点)的操作;但是有返回值,更方便,可以通过递归函数的返回值来移除节点,不需要额外操作;

​ 其次确定终止条件:修剪的操作并不是在终止条件进行的,所以就是遇到空节点返回就可以了;

​ 最后确定单层递归的逻辑:嫁接子树,此处不再赘述;

​ 递归代码如下:

	TreeNode* traversal(TreeNode* root, int L, int R){
        if(root == NULL)	return NULL;
        if(root->val < L){//节点值小于左边边界值
            TreeNode* tempNode = traversal(root->right, L, R);//此节点右子树中寻找所有大于L的值的节点,继续嵌套递归修剪右子树;
            return tempNode;
        }
        if(root->val > R)	return	traversal(root->left, L, R);//同理,并非直接return子树,而是修剪过后再return
        root->left = traversal(root->left, L, R);//对符合区间条件的根节点左右子树进行操作
        root->right = traversal(root->right, L, R);
        return root;
    }

将有序数组转换为二叉搜索树

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

108.将有序数组转换为二叉搜索树

​ 按题目要求切割数组得到平衡二叉搜索树,则从数组中间作为根节点开始切割;

​ 同时注意循环不变量,因为这里是需要不断对数组进行切割直到子数组的长度为一;

​ 遍历代码如下:

	TreeNode* traversal(vector<int>& nums, int L, int R){//确定函数参数和返回值
        //这里选择左闭右开的切割区间,则子区间停止切割的终止条件即是数组长度等于零的时候
        if(L >= R)	return NULL;
        //单层递归逻辑
        int mid = (R-L)/2+L;//防止int溢出
        TreeNode* root = new TreeNode(nums[mid]);//确定根节点
        root->left = traversal(nums, L, mid);//左闭右开
        root->right = traversal(nums, mid+1, R);
        return root;
    }

把二叉搜索树转化为累加树

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

节点的左子树仅包含键 小于 节点键的节点。 节点的右子树仅包含键 大于 节点键的节点。 左右子树也必须是二叉搜索树。

示例 1:

538.把二叉搜索树转换为累加树

  • 输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
  • 输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]

示例 2:

  • 输入:root = [0,null,1]
  • 输出:[1,null,1]

示例 3:

  • 输入:root = [1,0,2]
  • 输出:[3,3,2]

示例 4:

  • 输入:root = [3,2,4,1]
  • 输出:[7,9,4,10]

提示:

  • 树中的节点数介于 0 和 104 之间。
  • 每个节点的值介于 -104 和 104 之间。
  • 树中的所有值互不相同
  • 给定的树为二叉搜索树。

​ 如果给定的是一个有序数组,则[1, 2, 3, 4]的结果就是[10, 9, 7, 4],那二叉树呢?

​ 从二叉搜索树的最大值开始往前递加,无疑就是处理顺序的改变,即右中左的顺序来遍历整个二叉搜索树,即反中序遍历;

​ 则递归代码如下:

	int sum = 0;//记录前一个节点的数值
	void traversal(TreeNode* cur){//确定函数参数和返回值:遍历整棵树且无须对返回值进行处理
        if(!cur)	return;//确定终止条件:为空返回
        //if(cur->right)	sum += cur->right->val;	单层逻辑
        traversal(cur->right);
        cur->val += sum;
        sum = cur->val;//更新sum
        //if(cur->left)	sum += cur->left->val;
        traversal(cur->left);
    }

​ 整体代码如下:

/**
 * 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 {
private:
    int sum = 0;//记录前一个节点的数值
	void traversal(TreeNode* cur){//确定函数参数和返回值:遍历整棵树且无须对返回值进行处理
        if(!cur)	return;//确定终止条件:为空返回
        //if(cur->right)	sum += cur->right->val;	单层逻辑
        traversal(cur->right);
        cur->val += sum;
        sum = cur->val;//更新sum
        //if(cur->left)	sum += cur->left->val;
        traversal(cur->left);
    }
public:
    TreeNode* convertBST(TreeNode* root) {
        sum = 0;
        traversal(root);
        return root;
    }
};

总结

​ 递归和迭代的思想都要熟悉;

递归

​ 首先是熟知递归函数的参数和返回值:

​ 如何利用才能使算法的性能最优化,例如对返回节点类型、传入int替代vector;

​ (见Day 18)

​ 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值;(这种情况就是本文下半部分介绍的113.路径总和ii)

​ 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值; (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)

​ 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回;

​ 其次是关于递归函数的终止条件:

​ 有时候终止条件并不是简单的对处理节点判空即可,需要根据具体情境进行判断;

​ 最后是递归函数的单层遍历逻辑:

​ 二叉树题目的逻辑往往不算很难,大多时候可以理解为对一个遍历顺序特殊的数组进行处理,所以遍历顺序尤为重要;

​ 在构建二叉树的节点的时候,一定是选择从根节点开始(中左右),即前序遍历;

​ 在面对二叉搜索树时,一定是选择中序遍历(左中右),这样才能充分利用二叉搜索树的有序性质;

​ 求普通二叉树的属性的时候,一般采取后序遍历(左右中),因为需要返回中节点进行处理;

迭代

​ 迭代最主要的思想就是用栈来模拟树的逻辑,通过不断的push pop得到理想中的出栈顺序;

​ 一般在涉及到递归不是很好处理返回值的时候使用迭代,层序遍历就是一个典型的例子。

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

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

相关文章

iOS修改外部符号指针地址—fishhook原理

上篇文章解释了外部符号加载的原理&#xff0c;知道了外部函数地址最后都保存在__DATA_CONST,__got或__DATA,__lay_symbol_ptr。 因此我们如果想要hook外部函数&#xff0c;只需要在启动后修改这两个段内的值就行。 接下来就是怎么找到某个外部符号在__DATA_CONST,__got或__DA…

【MySQL笔记】InnoDB的插入缓存+非聚簇索引插入的离散性理解

文章目录 为什么需要插入缓存Insert Buffer非聚簇索引插入的离散性 Insert Buffer查看Insert Buffer信息 Insert Buffer的问题Change Buffer总结Reference 为什么需要插入缓存Insert Buffer 磁盘中的主键索引由于天然自增&#xff0c;无须磁盘的随机 I/O&#xff0c;只需不断追…

必示科技与日志易达成深度战略合作,携手共创智能运维新篇章

近日&#xff0c;智能运维企业必示科技与智能日志分析企业日志易达成深度战略合作&#xff0c;双方将在提升产品服务、技术融合创新应用、市场拓展、资源共享和协同效用等方面展开合作&#xff0c;为企业用户提供更全面优质的IT管理智能化服务&#xff0c;共同提升市场影响力&a…

【多线程】单例模式 | 饿汉模式 | 懒汉模式 | 指令重排序问题

文章目录 单例模式一、单例模式1.饿汉模式2.懒汉模式&#xff08;单线程&#xff09;3.懒汉模式&#xff08;多线程&#xff09;改进 4.指令重排序1.概念2.question:3.解决方法4总结&#xff1a; 单例模式 一、单例模式 单例&#xff0c;就是单个实例 在有些场景中&#xff0c…

半导体成品测试详述(Final Test,简称FT)

00、FT的一些概念 半导体成品测试&#xff08;Final Test&#xff0c;简称FT&#xff09;是在芯片封装完成后进行的最后一个测试阶段&#xff0c;其目的是确保芯片在实际应用中的性能和可靠性。FT测试可以包括环境测试、老化测试和应用特定的性能测试。 FT测试主要是为了解决各…

【快速上手STM32】SPI通信协议1.8寸TFT-LCD(ST7735S)

SPI简介 SPI&#xff0c;英文全称Serial Peripheral Interface&#xff0c;即串行外围设备接口&#xff0c;是一种高速、全双工、同步的串行通信总线。 我们之前说过I2C&#xff0c;那么我们就拿I2C和SPI做个对比。 SPI和I2C对比&#xff0c;优势在于SPI的传输速率比I2C快得…

shell脚本学习第一课

shell 简介 解析器 shell脚本基本使用

消息队列中间件,RabbitMQ的使用,死信队列,延迟队列,利用枚举实现队列,交换机,RountKey的声明

目录 0.交换机种类和区别 1.声明队列和交换机以及RountKey 2.初始化循环绑定 3.声明交换机 4.监听队列 4.1 监听普通队列 4.2监听死信队列 5.削峰填谷的实现 0.交换机种类和区别 Direct Exchange&#xff08;直连交换机&#xff09;&#xff1a; 直连交换机将消息发送到…

青铜器RDM研发管理平台 upload 任意文件上传漏洞复现

0x01 产品简介 青铜器RDM研发管理平台是集成产品管理、研发部门管理、研发项目管理、研发多项目管理、研发资源管理、研发绩效管理、研发工程管理的集中平台。 0x02 漏洞概述 青铜器RDM研发管理平台 upload 接口存在任意文件上传漏洞,未经身份验证的远程攻击者可通过该漏洞…

FreeSWITCH 1.10.10 简单图形化界面17 - ubuntu22.04或者debian12 安装FreeSWITCH(IamFree)

FreeSWITCH 1.10.10 简单图形化界面17 - ubuntu22.04或者debian12 安装FreeSWITCH 界面预览00、先看使用手册0、安装操作系统1、下载脚本2、开始安装3、登录网页 FreeSWITCH界面安装参考&#xff1a;https://blog.csdn.net/jia198810/article/details/132479324 界面预览 htt…

【Web】VS Code 插件

专栏文章索引&#xff1a;Web 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、安装步骤 二、插件 1.Chinese (Simplified) (简体中文) 2.open in browser 3.vscode-icons 4.Live Server 5.Live Server Preview 6.翻译(英汉词典) 一、安装步骤 点击 “扩…

Servlet的文件上传下载

Servlet的文件上传|下载 二、文件上传实现 2.1实现思路 需要使用到Commons-FileUpload组件需要将jsp页面form表单的enctype属性值设置为“multipart/form-data”&#xff0c;Servlet中使用IO流实现文件的上传 2.2、实现过程 2.2.1新建web项目导入jar包 <dependency>…

NLP的奥秘:用 Python 揭秘人类语言与人工智能的桥梁【6000 字长文含代码示例】

目录 NLP 的核心任务 NLP 的发展历史 NLP 的技术与方法 传统的 NLP 技术与方法 规则基础方法&#xff1a;语言学的智慧 统计学习方法&#xff1a;数据的力量 深度学习方法&#xff1a;人工智能的新浪潮 NLP 的应用领域 Python在 NLP 中的应用 1、NLTK (Natural Langu…

数字孪生与企业

数字孪生技术&#xff0c;简而言之&#xff0c;就是创造一个物理实体的数字双胞胎&#xff0c;在虚拟世界中精确模拟现实世界的行为、过程和系统。这种技术的核心在于&#xff0c;它允许我们在数字环境中实时地监控、分析和优化其物理对应物的性能和效率。数字孪生的应用场景极…

node.js服务器静态资源处理

前言&#xff1a;node.js服务器动态资源处理见 http://t.csdnimg.cn/9D8WN 一、什么是node.js服务器静态资源&#xff1f; 静态资源服务器指的是不会被服务器的动态运行所改变或者生成的文件. 它最初在服务器运行之前是什么样子, 到服务器结束运行时, 它还是那个样子. 比如平…

基于springboot+vue+Mysql的校园新闻网站

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

HarmonyOS实战开发-如何实现电话服务中发送短信的功能。

介绍 本示例使用ohos.telephony.sms 接口展示了电话服务中发送短信的功能。 效果预览 使用说明&#xff1a; 首页点击创建联系人&#xff0c;弹框输入联系人姓名和电话&#xff0c;点击确定按钮后&#xff0c;联系人列表中添加该联系人;点击管理&#xff0c;该按钮变成取消&…

[数据结构]——二叉树——堆的实现

1. 堆的概念及结构 如果有一个关键码的集合K { &#xff0c; &#xff0c; &#xff0c;…&#xff0c; }&#xff0c;把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中&#xff0c;并满足&#xff1a; < 且 < ( > 且 > ) i 0&#xff0c;1&…

如何使用OSI七层模型的思路进行Linux网络问题排障?

在运维工作中&#xff0c;我们可能经常遇到诸如服务器无法远程连接、网站无法访问等各种网络问题。此时你是否想过&#xff0c;我们常背的OSI七层模型&#xff0c;能在处理这样的实际问题中发挥什么样的作用呢&#xff1f; 基于OSI架构的方法论&#xff0c;我们可以使用自下而…

OpenHarmony轻量系统开发【5】驱动之GPIO点灯

5.1点灯例程源码 先看最简单得LED灯闪烁操作 源码结构如下&#xff1a; 第一个BUILD.gn文件内容&#xff1a; static_library("led_demo") {sources ["led_demo.c"]include_dirs ["//utils/native/lite/include","//kernel/liteos_m/c…