Day 20 654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

最大二叉树

给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:

  • 二叉树的根是数组中的最大元素。
  • 左子树是通过数组中最大值左边部分构造出的最大二叉树。
  • 右子树是通过数组中最大值右边部分构造出的最大二叉树。

通过给定的数组构建最大二叉树,并且输出这个树的根节点。

示例 :

654.最大二叉树

1 <= nums.length <= 1000

0 <= nums[i] <= 1000

nums 中的所有整数 互不相同

​ 构造过程如下:

​ 构造树一般采用的是前序遍历,因为先构造中间节点,然后递归构造左子树和右子树;

​ 遍历第一步,确定函数参数和返回值:

​ 参数传入的是存放元素的数组,返回该数组构造的二叉树的头结点,返回类型是指向节点的指针:

TreeNode* constructMaximumBinaryTree(vector<int>& nums)

​ 遍历第二步:

​ 确定终止条件,由于本题要求是用数组构建,且题目给出数组的长度大于等于一,所以不用考虑数组非空的情况;

​ 当数组长度为一时,说明此时遍历到了叶子节点,此时定义新节点并返回节点;

TreeNode* node = new TreeNode(0);
if (nums.size() == 1) {
    node->val = nums[0];
    return node;
}

​ 遍历第三步:

​ 确定单层遍历条件:
​ 由于需要数组最大值作为根节点,所以优先遍历整个数组获取最大值作为根节点,并得到这个最大值的下标作为分割边界;思路可以参考之前刚做过的中序后序构建二叉树一致,可以用新数组vector,也可以直接传入函数时定义两个int型变量记录左右区间,这里保持函数定义一致以vector型为例,若考虑代码性能选择后者;

	int MaxValue = 0;//获得数组最大值,由于题目给出条件数组为非负自然数,所以此处无须定义为INT_MIN
	int Index = 0;//定义最大值下标
	for(int i = 0; i < right - left/*nums.size()*/; i++){//遍历完毕,获得最大值
        if(nums[i] > MaxValue){
            MaxValue = nums[i];
            Index = i;
        }
    }
	TreeNode* node = new TreeNode(0);
	node->val = MaxValue;
	/*上述代码为"中"的处理过程*/
	if(Index > 0){//左子树不为空
        vector<int> newVec(nums.begin(), nums.begin() + maxValueIndex);
    	node->left = constructMaximumBinaryTree(newVec);
    }
	if(nums.size()- Index - 1 > 0){//右子树不为空
        vector<int> newVec(nums.begin() + maxValueIndex + 1, nums.end());
    	node->right = constructMaximumBinaryTree(newVec);
    }

​ 整体代码如下:

class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        TreeNode* node = new TreeNode(0);
        if (nums.size() == 1) {
            node->val = nums[0];
            return node;
        }
        // 找到数组中最大的值和对应的下标
        int maxValue = 0;
        int maxValueIndex = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] > maxValue) {
                maxValue = nums[i];
                maxValueIndex = i;
            }
        }
        node->val = maxValue;
        // 最大值所在的下标左区间 构造左子树
        if (maxValueIndex > 0) {
            vector<int> newVec(nums.begin(), nums.begin() + maxValueIndex);
            node->left = constructMaximumBinaryTree(newVec);
        }
        // 最大值所在的下标右区间 构造右子树
        if (maxValueIndex < (nums.size() - 1)) {
            vector<int> newVec(nums.begin() + maxValueIndex + 1, nums.end());
            node->right = constructMaximumBinaryTree(newVec);
        }
        return node;
    }
};

​ 提升代码性能,重写函数,整体代码如下:

class Solution{
private:
    	TreeNode* traversal(vector<int>& nums, int left, int right){
        if(left >= right)	return NULL;
        // 分割点下标:maxValueIndex
        int 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());
    }
};

合并二叉树

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。

你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

示例 1:

617.合并二叉树

注意: 合并必须从两个树的根节点开始。

​ 看起来操作两个二叉树第一次见,实际上在对称二叉树中已经使用过类似的思路了;

​ 合并二叉树,只需要同时遍历两个二叉树就可以了:

​ 代码实现(前序)如下:

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if (t1 == NULL) return t2; // 如果t1为空,合并之后就应该是t2
        if (t2 == NULL) return t1; // 如果t2为空,合并之后就应该是t1
        // 修改了t1的数值和结构
        t1->val += t2->val;                             // 中
        t1->left = mergeTrees(t1->left, t2->left);      // 左
        t1->right = mergeTrees(t1->right, t2->right);   // 右
        return t1;
    }
};

​ 本题前中后序都是可以的,前序最好理解;

​ 也可以采取构造新节点的方法:

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if (t1 == NULL) return t2;
        if (t2 == NULL) return t1;
        // 重新定义新的节点,不修改原有两个树的结构
        TreeNode* root = new TreeNode(0);
        root->val = t1->val + t2->val;
        root->left = mergeTrees(t1->left, t2->left);
        root->right = mergeTrees(t1->right, t2->right);
        return root;
    }
};

二叉搜索树中的搜索

给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。

例如,

700.二叉搜索树中的搜索

在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL。

​ 二叉搜索树是一个有序树:

​ 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;

​ 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

​ 它的左、右子树也分别为二叉搜索树;

例如,

[外链图片转存中…(img-V4uavmvL-1712591045263)]

在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL。

​ 二叉搜索树是一个有序树:

​ 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;

​ 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

​ 它的左、右子树也分别为二叉搜索树;

​ 这就决定了,二叉搜索树,递归遍历和迭代遍历和普通二叉树都不一样;

但是因为有序这一特性的存在,代码写起来是很简洁的;

	TreeNode* searchBST(TreeNode* root, int val){//函数参数和返回值
        //终止条件
        if(root == NULL || root->val == val)	return root;//中
        if(root->val > val)	return searchBST(root->left, val);//左
        if(root->val < val)	return searchBST(root->right, val);//右
        return NULL;
    }

​ 也可以用迭代法实现:

	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.验证二叉搜索树

​ 直观想法:中序遍历二叉树,判断数组是否递增即可;

	vector<int> res;	
	bool traversal(TreeNode* root){
        if(root == NULL)	return true;//空节点什么二叉树都是
        isBST(root->left);
        res.push_back(root->val);
        isBST(root->right);        
    }
	traversal(root);
	for (int i = 1; i < vec.size(); i++) {
    	// 注意要小于等于,搜索树里不能有相同元素
    	if (vec[i] <= vec[i - 1]) return false;
	}
	return true;

​ 若不使用数组辅助直接对二叉树进行操作,如何判断?

​ 很直白的一个想法

	if(root->val > root->left->val && root->val < root->right->val)	return ture;

​ **这么写就错了!**因为需要满足的不仅是大于子节点数值,而是整个子树节点的元素;

​ 这里可以采取一个最小值的全局变量,也可以直接使用双指针的思路来优化:

class Solution {
public:
    TreeNode* pre = NULL;
	bool isValidBST(TreeNode* root){
        if(root == NULL)    return true;
        bool left = isValidBST(root->left);
        if(pre != NULL && pre->val >= root->val)	return false;//当前一个节点大于等于后一个节点的时候,return false;
        pre = root;//记录前一个节点
        bool right = isValidBST(root->right);
        return left && right;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

苍穹外卖开发笔记(1.项目介绍和开发环境)

目录 一、项目介绍二、环境搭建1、web管理端前端部署2、后端环境搭建3、数据库搭建4、前后端联调5、导入接口文档 三、完善登录功能四、学习知识1、前端发送的请求&#xff0c;是如何请求到后端服务的&#xff1f; 一、项目介绍 二、环境搭建 由于本项目主要点在于学习后端开发…

头歌-机器学习 第13次实验 特征工程——共享单车之租赁需求预估

第1关&#xff1a;数据探索与可视化 任务描述 本关任务&#xff1a;编写python代码&#xff0c;完成一天中不同时间段的平均租赁数量的可视化功能。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a; 读取数据数据探索与可视化 读取数据 数据保存在./step1/…

如何使用Android手机通过JuiceSSH远程访问本地Linux服务器

文章目录 1. Linux安装cpolar2. 创建公网SSH连接地址3. JuiceSSH公网远程连接4. 固定连接SSH公网地址5. SSH固定地址连接测试 处于内网的虚拟机如何被外网访问呢?如何手机就能访问虚拟机呢? cpolarJuiceSSH 实现手机端远程连接Linux虚拟机(内网穿透,手机端连接Linux虚拟机) …

SSL中的CA证书

目录 一、CA概述 二、数据加密 三、身份认证 一、CA概述 SSL如何保证网络通信的安全和数据的完整性呢&#xff1f;就是采用了两种手段&#xff1a;身份认证和数据加密。身份认证就需要用到CA证书。 CA是证书的签发机构&#xff0c;它是公钥基础设施&#xff08;Public Key In…

Python --- Python + Vs code的安装与使用(windows平台)

Python Vs code的安装与使用 今天是我第一次开始尝试用Python&#xff0c;然后我想借此机会记录一下整个安装过程和上手过程。之前一直都是用的matlab&#xff0c;这个东西不仅大而且收费&#xff0c;但不可否认的是。matlab的很多东西都做的比较好&#xff0c;但我一直用的都…

经典文章:卷积神经网络的运作原理

https://brohrer.mcknote.com/zh-Hans/how_machine_learning_works/how_convolutional_neural_networks_work.html 参考资料 https://aitechtogether.com/article/38900.html https://www.ruanyifeng.com/blog/2017/07/neural-network.html http://neuralnetworksanddeeplea…

企业工商信息查询API接口有哪些

当今社会我们几乎每天都在和一些企业打交道&#xff0c;有时候需要确认下这家企业经营范围&#xff0c;注册地址等信息&#xff0c;那怎么办呢&#xff0c;这个时候就需要一些企业工商信息查询的API接口了。 有的时候你可以只知道这家公司的大概企业名称&#xff0c;比如数脉&…

springboot-开源项目-追踪法-简单有效,从F12到SQL数据库表

使用的技术栈&#xff1a;springbootmybatis&#xff0c;edge浏览器 插件&#xff1a;MybatisX 第一步&#xff1a; 按F12,选择网络 第二步&#xff1a; 进入IDEA编辑器&#xff0c;键盘按两次shift键&#xff0c;点击第一个&#xff0c;快速定位到该操作 3&#xff1a; 我…

锐化空间滤波器(提高清晰度的另一种方式)

书上一阶微分的定义可以理解&#xff0c;毕竟这里不死数学上的曲线的概念&#xff0c;而是像素点上的曲线。所以&#xff0c;不同于数学的严格单调递增曲线的导数是大于等于零&#xff0c;这里的严格单调递增曲线&#xff0c;只能是大于零。 至于二阶微分的定义&#xff0c;就…

子线程中创建 handler导致okhttp请求失败,从 ScheduledExecutorService 挖的坑开始

子线程创建方法1&#xff1a; ScheduledExecutorService schedulePool Executors.newScheduledThreadPool(2);schedulePool.schedule(new Runnable() {Overridepublic void run() {dorequest();}}, 2, TimeUnit.SECONDS); 子线程创建方法2&#xff1a; new Thread(new Runnab…

功能测试_验证新浪邮箱登录的正确性

案例&#xff1a;验证验证新浪邮箱登录的正确性 功能测试_等价类设计用例&#xff1a; 步骤&#xff1a; 1:明确需求&#xff1a;邮箱能否登录 2:划分等价类&#xff1a;有效等价类、有效取值、无效等价类、无效取值 3&#xff1a;提取数据编写用例&#xff1a;用例编号、…

带大家做一个,易上手的家常蒜蓉油麦菜

准备油麦菜 将最顶上 一点 和 根都去掉 然后 切成小段 时间足够 就用盐水用心清洗两遍 洗去表面的泥沙和虫卵 准备多一些蒜 切成碎末 起锅烧油 下蒜末 炒出蒜香味 然后 下入油麦菜翻炒 油麦菜会出水 等水烧的差不多 看油麦菜明显缩小后 下入小半勺盐 一点点白砂糖 翻炒均…

ssm041绿色农产品推广应用网站+vue

绿色农产品推广应用网站 摘 要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的…

第十四篇【传奇开心果系列】Python自动化办公库技术点案例示例:深度解读Python自动化处理图像

传奇开心果博文系列 系列博文目录Python自动化办公库技术点案例示例系列 博文目录前言一、Python自动化图像处理的优点介绍二、Python常用图像处理库和功能介绍三、强大且易于上手示例代码四、丰富的算法资源示例代码五、批量处理图片示例代码六、支持多种图像格式示例代码七、…

Mysql底层原理六:InnoDB 数据页结构

1.行格式 1.1 Compact行格式 1.1.1 示意图 1.1.2 准备一下 1&#xff09;建表 mysql> CREATE TABLE record_format_demo (-> c1 VARCHAR(10),-> c2 VARCHAR(10) NOT NULL,-> c3 CHAR(10),-> c4 VARCHAR(10)-> ) CHARSETascii ROW_FORMATCOM…

基于Yolov5的检测系统实战

文章目录 一、数据集 二、网络结构 三、完整文件目录介绍 四、测试分析 一、数据集 1、数据格式&#xff1a;图像数据&#xff08;JPG格式&#xff09;&#xff0c;采用labelme标注后的图像&#xff08;XML格式&#xff09;&#xff0c;训练需要的TXT格式 2、数据来源&…

【Python数据分析】让工作自动化起来,无所不能的Python

这里写目录标题 前言一、Python是办公自动化的重要工具二、Python是提升职场竞争力的利器三、Python是企业数字化的重要平台四、Python是AI发展的重要通道之一编辑推荐内容简介作者简介前言读者对象如何阅读本书目录 前言 随着我国企业数字化和信息化的深入&#xff0c;企业对…

[CSS]布局

盒子就是把网站分割成一小块一小块的吧&#xff0c;然后方便移动或者管理 布局属性 所谓的布局就是依靠css布局让html元素&#xff0c;可以按照UI设计师提供的设计稿进行HTML网页的内容排版并实现页面的布局效果。 布局的学习关键就是&#xff1a;1. 布局方式&#xff0c;2. …

SpringBoot+Vue,轻松实现网页版人脸登录与精准识别

目录 1、技术介绍 2、技术原理 2.1、人脸检测 ①参考模板法 ②人脸规则法 2.2、人脸跟踪 2.3、人脸比对 ①特征向量法 ②面纹模板法 识别过程 案例 一、springboot后端项目 1&#xff0c;拉取项目后&#xff0c;导入相关依赖jar包 2&#xff0c;执行sql文件夹下面…

Qt 中的项目文件解析和命名规范

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;QT❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、Qt项目文件解析 1、.pro 文件解析 2、widget.h 文件解析 3、main.cpp 文件解析 4、widget.cpp…