代码随想录算法训练营day20|654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树

devtools/2024/9/22 16:55:21/

最大二叉树

和昨日的依据后序和中序序列得到前序二叉树的例子相似,利用递归算法,每个递归体中查找数组中的最大值的位置,将序列分为左右,当传入数组大小为1时,传回以这个数组唯一元素构建的结点。具体写法如下。

class Solution {
public:TreeNode* constructMaximumBinaryTree(vector<int>& nums) {if(nums.size() == 0){return nullptr;}int index = -1;int max = INT_MIN;for(int i = 0; i<nums.size();i++){if(nums[i]>max){max = nums[i];index = i;}}//找到最大值vector<int>left(nums.begin(),nums.begin()+index);vector<int>right(nums.begin()+index+1,nums.end());TreeNode * root = new TreeNode(nums[index]);if(nums.size() == 1){TreeNode * root = new TreeNode(nums[0]);return root;}root->left = constructMaximumBinaryTree(left);root->right = constructMaximumBinaryTree(right);return root;}
};

优化后的写法

class Solution {
public:TreeNode* build(vector<int>& nums, int start, int end) {if(start == end){return nullptr;}int maxIndex = start;for(int i = start; i < end; i++){if(nums[i] > nums[maxIndex]){maxIndex = i;}}TreeNode* root = new TreeNode(nums[maxIndex]);root->left = build(nums, start, maxIndex);root->right = build(nums, maxIndex + 1, end);return root;}TreeNode* constructMaximumBinaryTree(vector<int>& nums) {return build(nums, 0, nums.size());}
};

算法的事件和空间复杂度均为O(n)。

合并二叉树

递归法

简单题,先判断两个二叉树是否存在空,若有一个为空,则返回另一个二叉树。

当两者均不为空的情况下,对左右子树进行前序遍历(从根节点开始),树1每个结点的val值加上树2每个结点的val。具体代码如下。

class Solution {
public:TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {if(root1 == nullptr){return root2;}//当树1为空,返回树2else if(root2 == nullptr){return root1;}//当树2为空,返回树1else{root1->val += root2->val;//树1结点的val值加上树2相应结点的val。 }root1->left = mergeTrees(root1->left,root2->left);root1->right = mergeTrees(root1->right,root2->right);return root1;}
};

算法的时间复杂度和空间复杂度为O(n)。

迭代方法

class Solution {
public:TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {if (!t1) return t2;if (!t2) return t1;stack<pair<TreeNode*, TreeNode*>> stk;stk.push({t1, t2});while (!stk.empty()) {auto p = stk.top();stk.pop();if (!p.first || !p.second) continue;p.first->val += p.second->val;if (!p.first->left) {p.first->left = p.second->left;} else {stk.push({p.first->left, p.second->left});}if (!p.first->right) {p.first->right = p.second->right;} else {stk.push({p.first->right, p.second->right});}}return t1;}
};

二叉搜索树中的搜索

递归,当当前结点与val相同或为空时,返回当前结点,当当前结点的值小于val,查询右子树,当当前结点的值大于val,查询左子树。

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

在二叉搜索树中查找一个结点的时间复杂度和空间复杂度取决于树的高度,当为平衡的二叉搜索树时,查找的时间复杂度和空间复杂度为O(logn),若不平衡,则最差变为一个链表,两者变为O(n)

验证二叉搜索树

考虑到结点的左子树全部小于结点,结点的右子树全部大于结点,采用左中右的中序遍历方式得到整体序列,判断序列递增情况即可验证二叉搜索树。(花了很久时间没想到只想到中序递归,唉)

class Solution {
public:vector<long> ans;void inorder(TreeNode*root,vector<long>&ans){if(root == nullptr){return;}inorder(root->left,ans);ans.push_back(root->val);inorder(root->right,ans);}bool isValidBST(TreeNode* root) {inorder(root,ans);for(int i = 1 ;i < ans.size(); i ++){if(ans[i] < ans[i-1]){return false;}}return true;}
};

或者直接中序遍历的时候进行比较。

class Solution {
public:TreeNode* prev = nullptr;bool isValidBST(TreeNode* root) {if (root == nullptr) {return true;}// 验证左子树if (!isValidBST(root->left)) {return false;}// 验证当前节点,如果前一个节点存在且当前节点的值不大于前一个节点的值,则不是BSTif (prev != nullptr && root->val <= prev->val) {return false;}// 更新前一个节点prev = root;// 验证右子树return isValidBST(root->right);}
};

这个方法相比前面的方法将算法的空间复杂度降为O(1),时间复杂度还是O(n)。

迭代法

参考代码随想录

代码随想录 (programmercarl.com)icon-default.png?t=N7T8https://programmercarl.com/0098.%E9%AA%8C%E8%AF%81%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.html#%E6%80%9D%E8%B7%AF

class Solution {
public:bool isValidBST(TreeNode* root) {stack<TreeNode*> st;TreeNode* cur = root;TreeNode* pre = NULL; // 记录前一个节点while (cur != NULL || !st.empty()) {if (cur != NULL) {st.push(cur);cur = cur->left;                // 左} else {cur = st.top();                 // 中st.pop();if (pre != NULL && cur->val <= pre->val)return false;pre = cur; //保存前一个访问的结点cur = cur->right;               // 右}}return true;}
};


http://www.ppmy.cn/devtools/43293.html

相关文章

202303青少年软件编程(Python)等级考试试卷(四级)

第 1 题 【单选题】 运行下列程序, 输出的结果是? ( ) def wenhao(name = zhejiang):print(hello + name)wenhao()A :hello B :hellozhejiang C :helloname D :程序将提示运行错误 正确答案:B 试题解析: 定义函数时, 可以指定形参的默认值。 如果在调用函数时给函数…

【区域脑图论文笔记】BrainNetCNN:第一个专门为脑网络连接体数据设计的深度学习框架

【区域脑图论文笔记】BrainNetCNN&#xff1a;第一个专门为脑网络连接体数据设计的深度学习框架 信息概览与提炼采用的数据与结果数据集结果概览一眼 重点图与方法概览核心与优劣总结模型与实验论文方法E2E的理解E2N的理解N2G的理解三个卷积层设计的理解 论文实验与讨论 总结与…

音视频及H264/H256编码相关原理

一、音视频封装格式原理&#xff1a; 我们播放的视频文件一般都是用一种封装格式封装起来的&#xff0c;封装格式的作用是什么呢&#xff1f;一般视频文件里不光有视频&#xff0c;还有音频&#xff0c;封装格式的作用就是把视频和音频打包起来。 所以我们先要解封装格式&#…

部署Prometheus + Grafana实现监控数据指标

1.1 Prometheus安装部署 Prometheus监控服务 主机名IP地址系统配置作用Prometheus192.168.110.27/24CentOS 7.94颗CPU 8G内存 100G硬盘Prometheus服务器grafana192.168.110.28/24CentOS 7.94颗CPU 8G内存 100G硬盘grafana服务器 监控机器 主机名IP地址系统配置k8s-master-0…

Go 实现 WebSocket 的双向通信

在Go语言中实现WebSocket的双向通信通常需要使用第三方库&#xff0c;其中 gorilla/websocket 是一个非常流行和广泛使用的库。 1、安装 go get github.com/gorilla/websocket 2、编写WebSocket服务器代码 package mainimport ("fmt""github.com/gorilla/we…

C++ 程序的基本要素

一 标识符 程序中变量、类型、函数和标号的名称称标识符。 a,b,name,int,char,main,void等。 系统已有的标识符称为关键字。 常见关键字 using,namespace,void,return; int,float,double,char,bool,signed,unsignex, long,short,const,true,false,sizeof if,else,for,do,whil…

教育学口诀解析

1) 卢梭爱自然&#xff0c;爱是《爱弥儿》&#xff0c;自然就是自然主义教育。夸美纽斯是教育遵循自然。 夸大自然拌饭&#xff0c;和 卢梭爱自然 2&#xff09; 陶行知的教育思想——两S一教&#xff0c;S是社会和生活首字的第一个字母。 陶行知的教育思想是结合了当时中国…

词法与语法分析器介绍

概述 词法和语法可以使用正则表达式和BNF范式表达&#xff0c;而最终描述文法含义的事状态转换图 Lex与YACC 词法分析器Lex 词法分析词Lex&#xff0c;是一种生成词法分析的工具&#xff0c;描述器是识别文本中词汇模式的程序&#xff0c;这些词汇模式是在特殊的句子结构中…