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

news2025/2/25 21:15:23

最大二叉树

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

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

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

示例 :

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;
    }
};

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

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

相关文章

django模板的继承

模板的继承 我们在访问一些访问的网站 这些网站页面整体都差不多 &#xff0c; 只是某一些局部在变化。 模板的继承&#xff0c; 就是自己先选好一个想要继承的模板页面 {% extends home.html %}​ 在继承之后子页面跟模板页面长的是一模一样的&#xff0c; 你需要在模板页面…

Burpsuite+MuMu模拟器12抓包

写在前面 高版本的安卓不能直接安装证书了&#xff0c;比较麻烦。步骤如下。 前置工作 安装adb https://blog.csdn.net/x2584179909/article/details/108319973 安装openssl https://blog.csdn.net/zyhse/article/details/108186278 下载证书 看一下自己的IP burp添加…

Linux Ubantu安装配置教程

Ubuntu是一个基于Linux的开源操作系统&#xff0c;它遵循GNU通用公共许可证&#xff0c;用户可以自由使用、复制、分发和修改。它提供直观易用的桌面环境&#xff0c;适合新手和有经验用户。Ubuntu有强大的软件中心&#xff0c;支持多硬件架构&#xff0c;注重安全和稳定&#…

AcWing 112. 雷达设备 解题思路及代码

先贴个题目&#xff1a; 以及原题链接&#xff1a; 112. 雷达设备 - AcWing题库https://www.acwing.com/problem/content/114/ 这题如果直接枚举点肯定是不行的&#xff0c;但可以把每个小岛的可能雷达设置点抽象成x轴上的线段进行贪心&#xff0c;我们的选点尽量选在线段的重合…

element vue 日期时间组件封装

一、背景 年、月、周、日的时间范围类型&#xff0c;选择对应的日期类型&#xff0c;会传参给后端一个dateType参数&#xff0c;用于后端判断&#xff0c;进行数据抽稀。 二、实现效果 三、代码 完整代码&#xff1a; //年月周日&#xff0c;组件封装 //vue3 setup <scrip…

element-ui中el-radio-group组件绑定点击事件触发多次的解决办法

1、需求 电商首页需求&#xff0c;需要做个单选框&#xff0c;然后点击选中切换图标方向及更换价格升倒序&#xff0c;如下图&#xff1a; 从官网文档看&#xff0c;单选框支持change event&#xff0c;使用click加载按钮处不会触发选中 但是使用 click.native 事件不做处理…

【XR806开发板试用】在 xr806 上移植 LVGL

本文参与极术社区的《基于安谋科技STAR-MC1的XR806开发板试用》活动。 不多废话&#xff0c;直接开搞&#xff0c;先上效果图 准备 开发环境啥的&#xff0c;已经有很多文章了&#xff0c;这里就不再提搭建开发环境的相关内容了。 一个屏幕(1.8’ 128x160) LVGL源码(v8.0.2…

ros 自定义package:在rviz中创建可显示markers的工具包(python)

在rviz中创建可显示markers的工具包 1. 创建using_makers工具包2. rviz部署和测试 1. 创建using_makers工具包 在catkin_ws工作空间下 cd ~/catkin_ws/srccatkin_create_pkg using_markers rospy visualization_msgsmkdir ~/catkin_ws/src/using_markers/scripts/添加basic_s…

D1084 5A低压差电压调整器应用方案,内含电流限制和热保护功能,防止任何过载时产生过高的结温

1、 概述&#xff1a; D1084是一款具有5A输出能力、低压差为1.5V的三端稳压器。输出电压可通过电位器调节或1.5V, 1.8V, 3.3V三个固定电压版。内含电流限制和热保护功能&#xff0c;防止任何过载时产生过高的结温。D1084系列电路有标准TO-220、TO-263和TO-252封装形式。 2、 典…

大话设计模式——21.中介者模式(Mediator Pattern)

简介 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用&#xff0c;从而使其耦合松散&#xff0c;而且可以独立地改变它们之间的交互 UML图 应用场景 大量的连接使得一个对象不可能在没有其他对象的支持下工作&#xff0c;系统表现为一个不可分割的…

redis过期监听机制

转自&#xff1a;https://www.cnblogs.com/wangyunhong/articles/16505079.html 1.redis配置 1.打开conf/redis.conf 文件&#xff0c;取消注释&#xff1a;notify-keyspace-events Ex 2.重启redis 3.如果设置了密码需要重置密码&#xff1a;config set requirepass **** 3…

新鲜出炉!这一套二手平台管理系统,太牛了,直接领取【带源码】

​今天给大家分享一套基于SpringbootVue的二手平台管理系统源码&#xff0c;在实际项目中可以直接复用。(免费提供&#xff0c;文末自取) 一、系统运行图&#xff08;设计报告和接口文档&#xff09; 1、登陆页面 2、后台页面 3、设计报告包含接口文档 二、系统搭建视频教程 …

JVM常用参数一

jvm启动参数 JVM&#xff08;Java虚拟机&#xff09;的启动参数是在启动JVM时可以设置的一些命令行参数。这些参数用于指定JVM的运行环境、内存分配、垃圾回收器以及其他选项。以下是一些常见的JVM启动参数&#xff1a; -Xms&#xff1a;设置JVM的初始堆大小。 -Xmx&#xff1…

了解CSS中的BFC以及用法

目录 一 常见的定位方案 1. 普通流&#xff08;所有元素默认为普通流的定位&#xff09; 2. 浮动 3. 绝对定位 二 BFC 1. 定义 2. 触发条件 3. 作用 &#xff08;1&#xff09; 避免外边距重叠 ​&#xff08;2&#xff09;清除浮动 &#xff08;3&#xff09; 阻…

【知识扫盲】DHCP Server扫盲与作用

DHCP Server在实际应用中非常广泛&#xff0c;它适用于各种规模的网络环境&#xff0c;从小型办公室到大型企业网络&#xff0c;都能发挥重要作用。以下是一些具体的使用场景&#xff0c;用通俗易懂的语言进行解释。 1. 办公室网络环境 在一家公司的办公室里&#xff0c;通常会…

麒麟KOS删除鼠标右键新建菜单里不需要的选项

原文链接&#xff1a;麒麟KOS删除鼠标右键新建菜单里不需要的选项 Hello&#xff0c;大家好啊&#xff01;在日常使用麒麟KOS操作系统时&#xff0c;我们可能会发现鼠标右键新建菜单里包含了一些不常用或者不需要的选项。这不仅影响我们的使用效率&#xff0c;也让菜单显得杂乱…

基于MPC的自动驾驶泊车控制

基于MPC的自动驾驶泊车控制 H. Ye, H. Jiang, S. Ma, B. Tang, and L. Wahab, “Linear model predictive control of automatic parking path tracking with soft constraints,” International Journal of Advanced Robotic Systems, vol. 16, no. 3, p. 附赠自动驾驶学习资…

Qt之QSS样式表

QSS简介 QSS&#xff08;Qt Style Sheet&#xff09;样式表是一种用于描述图形用户界面&#xff08;GUI&#xff09;样式的语言。它允许开发者为应用程序的控件定义视觉外观&#xff0c;例如颜色、字体、尺寸和布局等。 QSS 样式表的主要目的是提供一种简洁而灵活的方式来美化…

NzN的数据结构--栈的实现

在前面我们已经学习了哪些线性数据结构呢&#xff1f;大家一起来回顾一下&#xff1a;C语言学过的数组&#xff0c;数据结构中的线性表和顺序表和链表。那我们今天再来介绍数据结构里的两个线性结构--栈和队列。 目录 一、栈的概念及结构 二、用数组实现栈 1. 栈的初始化和…

Linux内核中常用的C语言技巧

Linux内核采用的是GCC编译器&#xff0c;GCC编译器除了支持ANSI C&#xff0c;还支持GNU C。在Linux内核中&#xff0c;许多地方都使用了GNU C语言的扩展特性&#xff0c;如typeof、__attribute__、__aligned、__builtin_等&#xff0c;这些都是GNU C语言的特性。 typeof 下面…