代码随想录算法训练营第二十一天(二叉树 八)

news2025/2/5 22:02:53

今天是二叉树复习最后一天!

力扣题部分:

669. 修剪二叉搜索树

题目链接:. - 力扣(LeetCode)

题面:

        给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。

        所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。

思路:

关于本题可以先看看下面关于昨天我写的这两道题的求解过程,不然很可能理解不了为什么代码能做到把树修剪并衔接起来。

两道题分别为昨天的701.二叉搜索树中的插入操作 和 450.删除二叉搜索树中的节点。

传送门:代码随想录算法训练营第二十天(二叉树 七)-CSDN博客

(递归三部曲)

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

这里我们为什么需要返回值呢?

因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是从二叉树中移除节点)的操作。

但是有返回值,更方便,可以通过递归函数的返回值来移除节点。

确定终止条件

修剪的操作并不是在终止条件上进行的,所以就是遇到空节点返回就可以了。

确定单层递归的逻辑

关于这个逻辑,我打算先从下面这段代码讲起。

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        if (root == nullptr || root->val < low || root->val > high) return nullptr;
        root->left = trimBST(root->left, low, high);
        root->right = trimBST(root->right, low, high);
        return root;
    }
};

这段代码直接想法就是:递归处理,然后遇到 root->val < low || root->val > high 的时候直接return NULL,一波修改,干净利落。乍一看好像没什么问题,然而这段代码有一个点没有考虑好,我们结合下图分析:

如果当前节点的左边的东西比low小,我们该怎么办呢?

上面那段的代码想的很简单:全部去除。

这样的做法很显然不对啊。按理来讲应该是把当前节点的左子树中寻找一个比low大的接上原来左子树根节点的位置(也就是上一行所谓当前节点的左边)。

加粗字讲的会有些含糊,但我们肯定能明白这道题涉及到重构不能简单的把小的全部舍去,因为小的节点里可能有比low大的节点存在,我们需要做的是把大的节点接上去而不是全部一刀砍死。

理解完这些我再具体讲一下下面这个图的代码的实现过程

(也就是这两个点怎么接上的)

如下代码相当于把节点0的右孩子(节点2)返回给上一层,

if (root->val < low) {
    TreeNode* right = trimBST(root->right, low, high); // 寻找符合区间[low, high]的节点
    return right;
}

然后如下代码相当于用节点3的左孩子 把下一层返回的 节点0的右孩子(节点2) 接住。

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

此时节点3的左孩子就变成了节点2,将节点0从二叉树中移除了。

这个接的过程有点难理解,但是本质和昨天的删除节点差不多,下面这段代码第一次大概理解思路就好,毕竟我第一遍也做不到手搓能出来的地步,更何况能讲的多明白。。希望大家能凑合着看(我自己也不是理解的很通透)。

代码实现:

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        if(!root) return nullptr;
        if(root -> val < low)
        {
            TreeNode* node = trimBST(root -> right, low, high);
            return node;
        }
        if(root -> val > high)
        {
            TreeNode* node = trimBST(root -> left, low, high);
            return node;
        }
        root -> left = trimBST(root -> left, low, high);
        root -> right = trimBST(root -> right, low, high);
        return root;
    }
};

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

题目链接:. - 力扣(LeetCode)

题面:

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 平衡二叉搜索树。

(平衡 要求指该树所有节点的左右子树的深度相差不超过 1。)

思路:

一听到数组转二叉搜索树,有的人可能会想到一个“馊主意”

例如 有序数组[-10,-3,0,5,9] 就可以构造成这样的二叉搜索树,如图

然而题目为了防止这种情况,强调了”平衡“二字。

其实弄一个平衡二叉搜索树也不难,将数组像二分查找一样分开递归创建就好了。

代码实现:

class Solution {
private:
    TreeNode* traversal(vector<int>& nums, int left, int right) {
        if (left > right) return nullptr;
        int mid = left + ((right - left) / 2);
        TreeNode* root = new TreeNode(nums[mid]);
        root->left = traversal(nums, left, mid - 1);
        root->right = traversal(nums, mid + 1, right);
        return root;
    }
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        TreeNode* root = traversal(nums, 0, nums.size() - 1);
        return root;
    }
};

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

题目链接:. - 力扣(LeetCode)

题面:

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

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

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

例子如图所示:

思路(递归):

这道题甚至不用递归三部曲,理解发现题目操作顺序就好做了。

根据示例,整个操作是从最大数8开始,然后找第二大的数7,第三大的数6.....

发现了吗?这个顺序,不刚好和中序遍历相反吗?

我们姑且称其为”反中序遍历“。

我们再设置一个全局变量count用来累加(初值为零),其他就没什么难点了,可以自己想想写写之后再比较一下下面的代码。

代码实现:

​
class Solution {
public:
    int count = 0;
    TreeNode* convertBST(TreeNode* root) {
        if(root == nullptr) return root;
        root -> right = convertBST(root -> right);
        root -> val += count;
        count = root -> val;
        root -> left = convertBST(root -> left);
        return root;
    }
};

​

二叉树总结

长达八篇文章的二叉树篇在此结尾!

二叉树给我的感觉就是递归有时候代码能很简洁,但是很难理解,迭代的话又有些麻烦篇幅没递归来的少,第一遍刷理解递归的会多一点,并且有的题目只能递归做。以前很多细节不明白打递归代码就只能靠玄学,靠自己感觉瞎打一通打不出来,但是通过这段时间的学习,至少递归三部曲能让我解题的时候想递归有一个过程,多做多理解,递归的代码就可以靠自己慢慢找感觉打出来了。

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

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

相关文章

使用 Dify 和 AI 大模型理解视频内容:Qwen 2 VL 72B

接下来的几篇相关的文章&#xff0c;聊聊使用 Dify 和 AI 大模型理解视频内容。 本篇作为第一篇内容&#xff0c;以昨天出圈的“黑神话悟空制作人采访视频”为例&#xff0c;先来聊聊经常被国外厂商拿来对比的国产模型&#xff1a;千问系列&#xff0c;以及它的内测版。 写在…

Linux非VP扩容方案

Linux系统非VP扩容方案 描述&#xff1a;现有虚拟机磁盘1TB 容量不够&#xff0c;需要扩容。 采用&#xff1a;https://bbs.sangfor.com.cn/forum.php?modviewthread&tid110403 扩容失败。原因是没有VP 和LV 解决方案&#xff1a; 1&#xff0c;查看分区 cat /proc/p…

鸿蒙内核源码分析(中断概念篇) | 海公公的日常工作

关于中断部分系列篇将用三篇详细说明整个过程. 中断概念篇 中断概念很多&#xff0c;比如中断控制器&#xff0c;中断源&#xff0c;中断向量&#xff0c;中断共享&#xff0c;中断处理程序等等.本篇做一次整理.先了解透概念才好理解中断过程.本篇的主角是海公公&#xff0c;用…

全国计算机二级C语言笔试试题及答案

一、选择题(每小题2分,共70分)   下列各题A)、B)、C)、D)四个选项中,只有一个选项是正确的。 请将正确选项填涂在答题卡相应位置上,答在试卷上不得分。   (1)下列叙述中正确的是 A)线性表的链式存储结构与顺序存储结构所需要的存储空间是相同的 …

day06-SpringBootWeb请求响应

前言 在上一次的课程中&#xff0c;我们开发了springbootweb的入门程序。 基于SpringBoot的方式开发一个web应用&#xff0c;浏览器发起请求 /hello 后 &#xff0c;给浏览器返回字符串 “Hello World ~”。 其实呢&#xff0c;是我们在浏览器发起请求&#xff0c;请求了我们的…

[Meachines] [Easy] Bastion SMB未授权访问+VHD虚拟硬盘挂载+注册表获取NTLM哈希+mRemoteNG远程管理工具权限提升

信息收集 IP AddressOpening Ports10.10.10.134TCP:22, 135, 139, 445, 5985, 47001, 49664, 49665, 49666, 49667, 49668, 49669, 49670 $ nmap -p- 10.10.10.134 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH fo…

Bonree ONE 3.0:全域可观测 运维新境界

2024年8月16日&#xff0c;备受瞩目的Bonree ONE 3.0产品发布会上海站在上海中心大厦隆重举行。此次发布会以”Take IT Easy“——全域可观测&#xff0c;运维新境界为主题&#xff0c;博睿数据正式发布了一体化智能可观测平台Bonree ONE 3.0版本。Bonree ONE 3.0凭借领先的全域…

超声波清洗机哪个品牌好用?值得入手的超声波清洗机品牌推荐

许多人初次使用超声波清洗机的场景&#xff0c;往往发生在眼镜店内。它能灵巧穿梭于眼镜鼻托等细微缝隙间&#xff0c;实现彻底清洁&#xff0c;成效显著。这不仅限于眼镜&#xff0c;各式小件物品同样能享受到这份深度洁净的待遇。尽管超声波清洗机或许并非日常生活中的绝对必…

LeetCode.80.删除有序数组中的重复项II

题目描述&#xff1a; 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在 原地 修改输入数组 并在使用 O(1) 额外空间…

【MySQL-23】万字总结<InnoDB引擎>——【逻辑存储结果&架构(内存结构,磁盘结构,后台线程)&事务原理&MVCC】

前言 大家好吖&#xff0c;欢迎来到 YY 滴MySQL系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Lin…

【nginx】详细详细超详细,包括编译安装nginx+升级+回滚+核心配置+高级配置+反向代理+Nginx Rewrite相关功能等等

理论部分&#xff1a; 企业高性能Web服务器Nginx是一个开源的、高性能的HTTP和反向代理服务器&#xff0c;同时也支持IMAP/POP3/SMTP协议。它由俄罗斯人Igor Sysoev开发&#xff0c;并在2004年以BSD-like协议发布。Nginx因其卓越的性能、稳定性、丰富的功能集以及简单的配置而…

连锁美业门店收银系统怎么选?什么样的美业系统好用?美业管理系统源码分享

通过“PCiPAD手机APP微信小程序”的便捷功能操作&#xff0c; 提升预约服务、 会员管理、 收银管理、 库存管理、 客勤维护、员工管理、 排班管理等流程效率&#xff0c; 让门店员工的工作重心回归到服务质量上。 ▲ 小程序 ▲ 手机APP ▲ PC管理后台

Aseembly(九)-[BX] Loop

正如本篇文章的标题所示:本篇文章主要是进行 [BX] 和loop的讲解 上篇文章我们讲述了 关于 自己去dosbox里面编写汇编程序并且一步一步的编译(masm) 链接(link) 然后进行debug的过程 ,也进行了一个关于栈的实验: 详情请见我的上一篇文章 Aseembly(八)-汇编语言编写程序 让我们…

JavaScript class和正则

正则表达式练习 出生日期 年 月 日 ()表示一个整体 console.log(1909.match(^19\\d{2}$)); console.log(2024.match(^20(([01][0-9])|(2[0-4]))$)); //年 console.log(1909.match(^(19\\d{2})|(20(([01][0-9])|(2[0-4])))$)); // 月 console.log(12.match(^(0[1-9])|(1[0-2])…

minio版本升级与数据迁移操作记录

系列文章目录 minio单节点与集群安装 文章目录 系列文章目录前言一、问题引出二、升级与数据迁移步骤0.资源清单1.部署及启动新minio单实例2.设置新旧实例的别名3.检查旧实例bucket及存储的文件4.通过mc客户端命令进行数据迁移5.迁移结果验证 三、新旧实例minio数据对比 前言 …

利用Geohash算法,快速检索周边兴趣点

文章目录 一、前言二、基本原理三、Geohash算法四、算法存在的问题五、代码实现六、问题解决处理 一、前言 需要一个需求&#xff0c;查找某小区附近的超市&#xff0c;如果该小区和超市距离在500米以内&#xff0c;则查找成功。 实现该功能按照传统方式&#xff0c;需要获取小…

【秒杀系统架构图】

文章目录 高并发防止超卖和恶意请求定时同步商品用户秒杀的流程秒杀服务的关注点&#xff1a; 秒杀系统一般出现正在电商平台中&#xff0c;秒杀系统需要支持高并发&#xff0c;保持一致性和高可用的特点&#xff1a; 高性能。 秒杀涉及大量的并发读和并发写&#xff0c;因此支…

QT:事件机制

一、事件机制 qt的核心机制&#xff1a;对象树、信号和槽、事件机制 1.1概念 就是当这件事情发生时&#xff0c;自动执行对应的功能代码。该某块功能代码是虚函数&#xff0c;只需重写该虚函数&#xff0c;即可执行重写的代码。 1.2事件处理简介 1. 什么是事件&#xff1f; (重…

algorithm算法库学习之——堆操作,最小/最大操作,比较操作,排列操作

algorithm此头文件是算法库的一部分。本篇介绍堆操作&#xff0c;最小/最大操作&#xff0c;比较操作&#xff0c;排列操作。 接口API 堆操作 is_heap 检查给定范围是否为一个最大堆 (函数模板) is_heap_until (C11) 查找能成为最大堆的最大子范围 (函数模板) make_heap 从一…

SQL 时间盲注 (injection 第十六关)

简介 SQL注入&#xff08;SQL Injection&#xff09;是一种常见的网络攻击方式&#xff0c;通过向SQL查询中插入恶意的SQL代码&#xff0c;攻击者可以操控数据库&#xff0c;SQL注入是一种代码注入攻击&#xff0c;其中攻击者将恶意的SQL代码插入到应用程序的输入字段中&#x…