代码随想录算法训练营第60期第十七天打卡

       今天我们继续进入二叉树的下一个章节,今天的内容我在写今天的博客前大致看了一下部分题目难度不算大,那我们就进入今天的题目。

第一题对应力扣编号为654的题目最大二叉树

       这道题目的坑相当多,我第一次题目没有看明白就是我不知道到底是如何构造出这棵二叉树的,我就直接看了视频讲解,现在我们先来看一下题目:

        我们先看一下示例是什么意思,注意力扣上是这样解释的:

        首先找出最大值,然后分割数组找到左边部分与右边部分然后递归构造出根节点的左子树与右子树就可以了,这样我才明白这道题目究竟是什么意思,既然要构造二叉树大家记住,我们大概率会选用前序遍历,为什么呢?因为我们构造二叉树一定是先要从根节点出发才能逐步构建起它的左子树与右子树进而递归构造出整棵二叉树,这个是大家一定要去了解的,后来看完讲解我发现这道题与我们昨天的最后一道题有异曲同工之妙,其实都还是递归构建,当然我们这里是需要先找出最大的元素作为根节点,随后我们就可以找到左子树与右子树,递归构建就可以了,我要说明一下注意我们后来的数组是左闭右开的,一定注意,我们传入数组递归构建就可以,我将代码放到下面大家可以自行参考:

class Solution {
public:TreeNode* constructMaximumBinaryTree(vector<int>& nums) {TreeNode* node = new TreeNode(0);//特殊情况要考虑上不要忘记if (nums.size() == 1) return new TreeNode(nums[0]);//那为什么没有考虑数组为空的情况呢?因为题目说了数组的大小是大于等于1的int maxValue = 0;//定义最大值int index = 0;//定义最大值的下标for (int i = 0; i < nums.size(); ++i){if (nums[i] > maxValue){maxValue = nums[i];index = i;}}node -> val = maxValue;//构造左子树if (index > 0){vector<int> newVec(nums.begin(), nums.begin() + index);node->left = constructMaximumBinaryTree(newVec);}//构造右子树if (index < (nums.size() - 1)){vector<int> newVec(nums.begin() + index + 1, nums.end());node -> right = constructMaximumBinaryTree(newVec);}return node;}
};

       那其实这道题目还有优化版本的代码大家可以发现我需要构造新的数组来存储左右子数,这样其实又耗时又耗空间,这里我再给出优化版的代码:

class Solution {
private:// 在左闭右开区间[left, right),构造二叉树TreeNode* traversal(vector<int>& nums, int left, int right) {if (left >= right) return nullptr;// 分割点下标:maxValueIndexint maxValueIndex = left;for (int i = left + 1; i < right; ++i) {if (nums[i] > nums[maxValueIndex]) maxValueIndex = i;}TreeNode* root = new TreeNode(nums[maxValueIndex]);// 左闭右开:[left, maxValueIndex)root->left = traversal(nums, left, maxValueIndex);// 左闭右开:[maxValueIndex + 1, right)root->right = traversal(nums, maxValueIndex + 1, right);return root;}
public:TreeNode* constructMaximumBinaryTree(vector<int>& nums) {return traversal(nums, 0, nums.size());}
};

        这样就可以避免申请新的空间来重新建立数组,我们直接使用下标操作,不过建议大家先把最基础的版本搞明白其实就可以了。这道题目我就先分享到这里,接下来我们看下一道题目。

第二题对应力扣编号为617的题目合并二叉树

        那这道题是什么意思呢?其实是将两棵树相对应位置的节点的数值相加最后可以得到一棵新的二叉树,我们来看一下具体的题目:

        我们应该如何考虑这道题目呢?其实这道题目难点就在于它是同时操作两棵二叉树,而我们平时刷的题都是操作一棵二叉树,但是我希望这道题过后大家可以掌握应该如何同时操作两棵二叉树,首先大家要知道一点就是如果我在合并的过程中我如果其中一棵二叉树的当前的节点是空,其实我的新合并出来的二叉树就应该是另一棵二叉树的所对应节点的值,如果两棵二叉树都为空,那其实新二叉树的对应节点也为空,随后我们递归构建左子树与右子树就可以,最后返回根节点,当然我下面提供的代码是我在tree1的基础上更新,其实大家也可以开一棵新的二叉树,在这里我就提供一下更新版本的代码,如果开新的二叉树版本大家感兴趣的话可以去代码随想录网站去看:

class Solution {
public:TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {if (root1 == NULL) return root2;if (root2 == NULL) return root1;//if (root1 == NULL && root2 == NULL) return NULL;//其实两棵树的对应节点都为空的情况已经包含了(上面这一句可以不写)root1 -> val += root2 -> val;root1 -> left = mergeTrees(root1 -> left, root2 -> left);root1 -> right = mergeTrees(root1 -> right, root2 -> right);return root1;}
};

第三题对应力扣编号为700的二叉搜索树中的搜索

         在这里我们就引入了二叉搜索树了,我们先复习一下什么样的树叫做二叉搜索树,其实是左子树的所有数值小于根节点,右子树的所有数值大于根节点就是二叉搜索树,我们了解了定义以后我们一起来看一下题目:

       我看到示例就大致明白了题目的具体要求了,其实题目给我们的是一个层序遍历和一个节点的值,要求我们返回以该节点为根的子树,那我们如何解决这道题目呢?其实这道题目的递归法与迭代法都不难理解,我两种思路都给大家展示一下,首先题目就很好利用了二叉搜索树的性质,其实我们是可以利用二叉搜索树的性质来判断我们当前搜索的是在左子树还是右子树,就是与根节点的值进行比较,如果小就说明我们目前在左子树,如果大说明我们目前在右子树,那这样我们可以写出如下的递归代码:

class Solution {
public:TreeNode* searchBST(TreeNode* root, int val) {if (root == NULL || root -> val == val) return root;TreeNode* result = NULL;//这时候在左子树if (root -> val > val){//注意我们使用一个临时变量来存储我们找到的值result = searchBST(root -> left, val);}//这时候在右子树 else if (root -> val < val){result = searchBST(root -> right, val);}return result;}
};

          接下来我们来看一下迭代法如何写,其实我们原来是不是写过迭代法,我们一些用到迭代法都是会用栈或者队列去模拟深度遍历和广度遍历,但这里我们考虑到二叉搜索树的特殊性,其实我们不需要这么麻烦了,它的节点是有序的我们就不需要四处搜索了,我们看一下代码是如何写的:

class Solution {
public:TreeNode* searchBST(TreeNode* root, int val) {while (root != NULL) {if (root->val > val) root = root->left;else if (root->val < val) root = root->right;else return root;}return NULL;}
};

第四题验证二叉搜索树对应力扣编号98

        我们上一道题已经刷到过关于二叉搜索树的题目,这一道题是让我们验证二叉搜索树,我们看一下题目到底是怎么说的:

        其实题目要求很简单了,那么我们应该如何解决呢?其实这道题目有点那种数学题的感觉叫做“会者不难,难者不会”,我为啥这样说呢?因为如果大家知道一个二叉搜索树的性质其实就很简单了,我直接告诉大家,大家以后记住就可以了“中序遍历下,输出的二叉搜索树节点的数值是有序序列”,只要大家知道这个性质其实代码就很好写了,我们使用我们之前的迭代写法将这棵树的中序遍历的结果存储到一个数组里,然后判断这个数组是否有序就可以了,我可以直接给出代码:

class Solution {
private:vector<int> vec;void traversal(TreeNode *root){if (root == NULL) return;//左根右的中序遍历if (root -> left) traversal(root -> left);vec.push_back(root -> val);if (root -> right) traversal(root -> right);}
public:bool isValidBST(TreeNode* root) {vec.clear();//先清空traversal(root);//这样其实就将数组再次填满了for (int i = 1; i < vec.size(); ++i){if (vec[i] <= vec[i - 1]) return false;}return true;}
};

      这是一种最为直观的做法,大家务必要将这个技巧牢记于心,那其实还有其他方法,我们还是要注意我们二叉搜索树是左子树所有的节点都是小于根节点的,右子树所有的节点都是大于根节点的,千万不要不判断根节点与它的左右孩子的关系,这样是无法判断是不是二叉搜索树的,因为不符合我们二叉搜索树的定义,那我们应该如何判断呢?其实我们还是可以使用递归的,我们其实可以一直中序遍历,只要发现没有顺序的就可以直接return false,那我们的代码可以这样写:

class Solution {
public:long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值bool isValidBST(TreeNode* root) {if (root == NULL) return true;bool left = isValidBST(root->left);// 中序遍历,验证遍历的元素是不是从小到大if (maxVal < root->val) maxVal = root->val;else return false;bool right = isValidBST(root->right);return left && right;}
};

       就是说我们一直更新maxVal如果左子树的节点小于根节点的值那我就一直赋值如果发现有大于的这在左子树这边就说明不是二叉搜索树了,我们来看一下代码:

class Solution {
public:long long maxVal = LONG_MIN;bool isValidBST(TreeNode* root) {if (root == NULL) return true;bool left = isValidBST(root -> left);if (maxVal < root -> val) maxVal = root -> val;else return false;bool right = isValidBST(root -> right);return left && right;}
};

        这个其实还是中序遍历,左根右的顺序,我们先看左子树,只要当前节点不为空就一直递归,先左再右,最后发现到了叶子节点,最后将根节点赋值给maxVal,接着去判断右边,如果最后左右都为true就是二叉搜索树了,这个递归还有点难度,就是我们是如何递归的,先左一直到叶子节点会返回true,随后我们赋值,再去判断右子树,当右子树也到了叶子节点的时候也会返回 true,根节点的右子树是一个意思,最后我们判断是否是true, 我还是建议大家用上面的第一种方法理解,这个递归作为选学,上面的那一种方法必须会。

总结

        今天的题目还是挺有意思的,我们也接触了二叉搜索树,最大二叉树是一道不错的题目,我们学会了递归与分割数组,合并二叉树其实还是递归,随后的两道题我们接触了二叉搜索树,大家自己要去消化一下,我们明天再见!

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

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

相关文章

Burp靶场JWT学习笔记1

JWT(JSON Web Token) 从其名字就可以看出来&#xff0c;它具有表示身份的作用&#xff0c;其本质是将用户信息储存到一串json字符串中再将其编码得到一串token JWT由三部分组成&#xff0c;分别是 Header&#xff0c;Payload&#xff0c;Signatrue JWTBase64(Header).Base6…

第53.5讲 | 小项目实战:用 SHAP 值解释农作物产量预测模型 [特殊字符][特殊字符]

目录 ✅ 项目背景 &#x1f4e6; 所用工具 &#x1f4c1; 数据字段&#xff08;模拟&#xff09; &#x1f9d1;‍&#x1f4bb; 代码实现步骤 &#x1f3af; 解读与启发 &#x1f9e0; 项目拓展建议 ✅ 项目背景 我们使用一个简化的玉米产量数据集&#xff08;可模拟实…

极狐GitLab 合并请求依赖如何解决?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;关于中文参考文档和资料有&#xff1a; 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 合并请求依赖 (PREMIUM ALL) 在极狐GitLab 16.6 中引入了对复杂合并依赖关系的支持&#xff0c;通过名为 remove_mr_blockin…

Django DRF实现用户数据权限控制

在 Django DRF 中使用 ModelViewSet 时&#xff0c;若需实现用户仅能查看和操作自己的数据详情&#xff0c;同时允许所有认证用户访问列表&#xff0c;需结合权限类和动态权限分配。以下是具体步骤&#xff1a; 1. 自定义对象权限类 创建一个 IsOwner 权限类&#xff0c;检查…

【数据结构】——线性表之单链表

一、单链表的概念和结构 1、单链表的概念&#xff1a; 链表也是属于我们的线性表中的一种&#xff0c;其物理结构上是不一定连续的&#xff0c;但是逻辑结构上是一定连续的&#xff0c;所以其是没办法像前面的顺序表一样通过找到下一个元素的&#xff0c;其是通过指针来找到下…

线程函数库

pthread_create函数 pthread_create 是 POSIX 线程库&#xff08;pthread&#xff09;中的一个函数&#xff0c;用于创建一个新的线程。 头文件 #include <pthread.h> 函数原型 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*s…

2.5 桥梁桥面系及附属结构施工

2.5.1 桥面系施工 1.排水设施 设置纵横坡及泄水孔&#xff0c;减少桥面积水、防排结合。汇水槽、泄水孔顶面高程低于桥面铺装10-15mm。泄水孔边缘设渗水盲沟泄水管下端至少应伸出构筑物底面100-150mm。泄水管通过竖向管道直接引至地面或雨水管线。竖向管道抱箍、卡环、定位卡…

docker 代理配置冲突问题

问题描述 执行 systemctl show --property=Environment docker 命令看到有如下代理配置 sudo systemctl show --property=Environment docker Environment=HTTP_PROXY=http://127.0.0.1:65001 HTTPS_PROXY=http://127.0.0.1:65001 NO_PROXY=127.0.0.1,docker.io,ghcr.io,uhub…

MATLAB基础应用精讲-【基础知识篇】发布和共享 MATLAB 代码

目录 MATLAB发布代码---生成文档pdf 分节符对发布文件的分节 实时脚本 Matlab workspace与m脚本数据共享 发布和共享 MATLAB 代码 在实时编辑器中创建和共享实时脚本 发布 MATLAB 代码文件 (.m) 添加帮助和创建文档 发布 MATLAB 代码文件 (.m) 可创建包括您的代码、注释…

JDBC 批处理与事务处理:提升数据操作效率与一致性的密钥

目录 一. JDBC批量添加数据 1. 什么是批量添加数据 2. 实现数据的批量添加 a. 方式一&#xff1a;不分块 二. JDBC事务处理 1. 什么是事务 2. JDBC事务处理实现 三. 总结 前言 本文来讲解JDBC的批处理和事务处理 这对数据的安全性和准确性以及高效率提供很好的办法 话不…

C++实现Atbash密码

详细说明 埃特巴什密码是一种替换密码&#xff0c;在该密码中字母表中的字母是反向对应的。例如&#xff0c;A 会被替换为 Z&#xff0c;B 会被替换为 Y&#xff0c;依此类推。 #include <cassert> /// for assert #include <iostream> /// for IO operations #…

QuecPython+GNSS:实现快速定位

概述 QuecPython 结合 GNSS&#xff08;全球导航卫星系统&#xff09;模块为物联网设备提供开箱即用的定位能力解决方案。该方案支持 GPS/北斗/GLONASS/Galileo 多系统联合定位&#xff0c;为物联网开发者提供从硬件接入到云端服务的全栈式定位解决方案。 优势特点 多体系定…

leetcode刷题日记——逆波兰表达式求值

[ 题目描述 ]&#xff1a; [ 思路 ]&#xff1a; 借助栈的特性&#xff0c;遇见数字就将这个数压入栈内&#xff0c;遇见符号&#xff0c;就从栈中弹出两个数&#xff0c;进行相应的运算&#xff0c;然后将结果压入栈中运行如下 int evalRPN(char** tokens, int tokensSize…

firewalld 详解

firewalld 详解 firewalld 是 Linux 系统中一个动态防火墙管理工具&#xff0c;取代了传统的 iptables&#xff0c;提供更灵活、动态的规则配置&#xff0c;支持运行时修改且无需重载服务。以下是其核心概念、常用操作及示例指南&#xff1a; 一、核心概念 区域&#xff08;Zo…

面向高性能运动控制的MCU:架构创新、算法优化与应用分析

摘要&#xff1a;现代工业自动化、汽车电子以及商业航天等领域对运动控制MCU的性能要求不断提升。本文以国科安芯的MCU芯片AS32A601为例&#xff0c;从架构创新、算法优化到实际应用案例&#xff0c;全方位展示其在高性能运动控制领域的优势与潜力。该MCU以32位RISC-V指令集为基…

支付宝小程序组件与页面构造器使用指南:从页面到组件的正确迁移

引言 在支付宝小程序开发中&#xff0c;我们经常会遇到需要将页面组件化的情况。本文将通过一个实际案例&#xff08;将 /pages/plugin/device 从页面迁移到组件&#xff09;&#xff0c;深入分析支付宝小程序中页面和组件的区别&#xff0c;以及正确的迁移方式。我们将从问题…

26-算法打卡-字符串-右旋字符串-第二十六天

1 题目说明 字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k&#xff0c;请编写一个函数&#xff0c;将字符串中的后面 k 个字符移到字符串的前面&#xff0c;实现字符串的右旋转操作。 例如&#xff0c;对于输入字符串 &qu…

fastbev mmdetection3D 角度和方向损失

角度/方向损失 sin(a−b)sinacosb−cosasinb config参数 dir_offset0.7854, # pi/4 dir_limit_offset0, box编解码 # Copyright (c) OpenMMLab. All rights reserved. import torchfrom mmdet.core.bbox import BaseBBoxCoder from mmdet.core.bbox.builder import BBOX_COD…

极狐GitLab 如何 cherry-pick 变更?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;关于中文参考文档和资料有&#xff1a; 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 拣选(cherry-pick)更改 (BASIC ALL) 在 Git 中&#xff0c;cherry-pick 是从一个分支获取一个提交并将其添加为另一个分支的…

java多线程(7.0)

目录 ​编辑 定时器 定时器的使用 三.定时器的实现 MyTimer 3.1 分析思路 1. 创建执行任务的类。 2. 管理任务 3. 执行任务 3.2 线程安全问题 定时器 定时器是软件开发中的一个重要组件. 类似于一个 "闹钟". 达到一个设定的时间之后, 就执行某个指定好的…