热门标签 | HotTags
当前位置:  开发笔记 > 人工智能 > 正文

力扣98验证二叉搜索树

二叉搜索树,也叫二叉排序树,满足以下性质:对于任意节点,(如果有)左子节点小于当前节点,右子节点大于当前节点算法思路也是递归吗?递归地去判断左右子节点与当前节点的大小官方题解

二叉搜索树,也叫二叉排序树,满足以下性质:



  1. 对于任意节点,(如果有)左子节点小于当前节点,右子节点大于当前节点


算法思路

也是递归吗?递归地去判断左右子节点与当前节点的大小

官方题解中更巧妙的办法是:中序遍历,基于以下性质



  • 二叉搜索树的中序遍历一定是升序序列

    只需要在中序遍历的过程中,每一步去判断当前值是否大于上一个值就行


递归做法

class Solution {
public:
// 这里为什么用long long呢?主要是节点值取值范围刚好就是int的范围
bool helper(TreeNode* root, long lower, long upper) {
if (root == nullptr) {
return true;
// 当直到再没子节点也没有违反规则
}
if (root->val <= lower || root->val >= upper) {
return false;
// 这里是跟节点值位于开区间内才会通过,如果是int,那么INT_MAX刚好就等于边界条件,无法通过
// 但是long不行吗?不至于long long 吧
}
return helper(root->left, lower, root->val) && helper(root->right, root->val, upper);
// 这里比较的其实是当前节点与他的左右父节点,没有就是祖父左右节点,都没有就是初始正负边界值
}
bool isValidBST(TreeNode* root) {
return helper(root, LONG_MIN, LONG_MAX);
}
};



但是空间效率很差,递归深了是很费内存的


中序遍历


复习中序遍历

class Solution {
public:
vector inorderTraversal(TreeNode* root) {
vector res;
stack stack;
// 当栈不空或不为空节点,这里或只是保证root!=nullptr能进去
// 这两个while循环写得…如果只满足条件一执行出栈操作肯定没问题
// 如果只满足条件二,那么至少有一步压栈操作(当前根节点),执行出栈也不会有问题
while (!stack.empty() || root != nullptr) {
while (root != nullptr) {
// 递归地把当前节点路径下的所有左子节点入栈
stack.emplace(root);
root = root->left;
// 循环结束,root更新为最深的左子节点的左节点,即为空
}
// 取出栈顶元素
root = stack.top();
stack.pop();

res.emplace_back(root->val);// 插入最深左节点的值
// 最深左节点一定没有左子节点,那么它其实就相当于“中”,接下来是右
// 下一次循环中又以右节点为根节点,去递归压它的左节点
root = root->right;
}
return res;
}
};

题解

只是上面的中序遍历稍作改动

class Solution {
public:
bool isValidBST(TreeNode* root) {
// 用栈来模拟中序遍历
// 之前写的中序遍历用的很简单的递归,迭代感觉比较难
// 这么说的“递归写法相当于隐式维护了一个栈,而迭代就是要把这个栈写出来”
stack stack;
// 排除边界条件
// 为什么这里要减一?上一个解法都没有减一,上一个是LONG_MIN
// long long inorder = INT_MIN - 1;// 这里只保存一步中序遍历的结果
long inorder = LONG_MIN;
while (!stack.empty() || root != nullptr) {
while (root != nullptr) {
// 当节点不为空就压入栈中
stack.push(root);
// 递归地去压左节点?
root = root->left;
}
root = stack.top();
stack.pop();
// 小于前一个中序遍历得到的值,说明不是升序序列,即不是二叉搜索树
if (root->val <= inorder) {
return false;
}
inorder = root->val;// 保存一步中序遍历值
root = root->right;
}
return true;
}
};

时间效率低了很多,空间有比较大的改善,但是仍然不算好



推荐阅读
  • ML学习笔记20210824分类算法模型选择与调优
    3.模型选择和调优3.1交叉验证定义目的为了让模型得精度更加可信3.2超参数搜索GridSearch对K值进行选择。k[1,2,3,4,5,6]循环遍历搜索。API参数1& ... [详细]
  • 应对.avast后缀勒索病毒:全面指南
    本文详细介绍了.avast后缀勒索病毒的特性、感染途径、恢复方法及预防措施,旨在帮助用户有效应对这一威胁。 ... [详细]
  • 解决vCenter vSphere HA初始化失败的问题
    本文探讨了在集群中遇到的所有vSphere HA主机状态显示‘无法正确安装或配置vSphere HA代理’错误的情况,并详细介绍了排查与解决步骤,包括检查HA初始化错误及安装HA代理的常见故障排除方法。 ... [详细]
  • 本文详细探讨了Java命令行参数的概念、使用方法及在实际编程中的应用,包括如何通过命令行传递参数给Java程序,以及如何在Java程序中解析这些参数。 ... [详细]
  • 本文详细介绍了Java的安装、配置、运行流程以及有效的学习方法,旨在帮助初学者快速上手Java编程。 ... [详细]
  • 探讨如何使用 JavaScript 将两个时间戳的差值精确转换为天数、小时和分钟的格式。 ... [详细]
  • 本文探讨了Hive作业中Map任务数量的确定方式,主要涉及HiveInputFormat和CombineHiveInputFormat两种InputFormat的分片计算逻辑。通过调整相关参数,可以有效控制Map任务的数量,进而优化Hive作业的性能。 ... [详细]
  • 深入解析BookKeeper的设计与应用场景
    本文介绍了由Yahoo在2009年开发并于2011年开源的BookKeeper技术。BookKeeper是一种高效且可靠的日志流存储解决方案,广泛应用于需要高性能和强数据持久性的场景。 ... [详细]
  • 想搭建一个能够稳定支持每日500万页面浏览量(PV)的网站架构吗?了解500万PV的实际意义,以及如何计算服务器需要处理的并发请求量,是成功构建高效架构的关键。本文将从基础概念出发,深入探讨实现这一目标所需的技术细节和策略。 ... [详细]
  • 传送门A-Registration#include#definelllonglongusingnamespacestd;chars[15],t[15]; ... [详细]
  • 本文探讨了2019年前端技术的发展趋势,包括工具化、配置化和泛前端化等方面,并提供了详细的学习路线和职业规划建议。 ... [详细]
  • 写在前面,排序算法属于面试中绝对不会错过的一道题,不管是原理,手撕,变形,优化,全都是考点。接 ... [详细]
  • 文章目录STDEV.PSTDEV.S展示释义STDEV.P计算总体的标准差(StandardDeviationForPopulation),公式如下:Var(x)∑i1n(xi−E ... [详细]
  • HTTPS与TLS/SSL协议详解:握手及记录协议
    HTTPS,即HTTP over TLS/SSL,通过在HTTP通信层引入安全协议,确保数据传输的安全性。本文将深入探讨TLS/SSL协议的基本概念、HTTPS的必要性,以及TLS握手和记录协议的工作原理。 ... [详细]
  • Barbican 是 OpenStack 社区的核心项目之一,旨在为各种环境下的云服务提供全面的密钥管理解决方案。 ... [详细]
author-avatar
潘昀湖5159
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有