Leetcode 98:验证二叉搜索树

  • 题目描述
  • 我的解法:非递归的中序遍历
  • 其它解法1:非递归的中序遍历,用LONG_MIN规避树的val等于INT_MIN的情况
  • 其他解法2:递归的中序遍历思想
  • 其它解法3:即时比较的递归中序遍历
  • 其它解法4:节点继承法

题目描述

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

  • 节点的左子树只包含小于当前节点的数。
  • 节点的右子树只包含大于当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

示例1:

输入:2/ \1   3
输出: true

示例2:

输入:5/ \1   4/ \3   6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。根节点的值为 5 ,但是其右子节点值为 4 。

我的解法:非递归的中序遍历

利用中序遍历思想,代码见下

bool isValidBST(TreeNode* root) {TreeNode* p = root;stack<TreeNode*> s;int temp = 233333;  // 随便设置的,无意义bool isTempUpdate = false;while (p != NULL || !s.empty()){while (p != NULL){s.push(p);p = p->left;}if (!s.empty()){p = s.top();if (isTempUpdate && temp >= p->val) return false;temp = p->val;isTempUpdate = true;s.pop();p = p->right;}}return true;
}

一开始代码中并没有isTempUpdate这个bool变量,而是直接把INT_MIN赋值给temp,在输入是[-2147483648]的时候报错了,因为INT_MIN值就是-2147483648,在执行循环时temp的初始值和树的val相等,返回false。
一开始的代码见下:

bool isValidBST(TreeNode* root) {TreeNode* p = root;stack<TreeNode*> s;int temp = INT_MIN;while (p != NULL || !s.empty()){while (p != NULL){s.push(p);p = p->left;}if (!s.empty()){p = s.top();if (temp >= p->val) return false;temp = p->val;s.pop();p = p->right;}}return true;
}

为了解决这个问题,我加上了一个bool类型变量以记录temp的值是否更新过,只有当其值更新过且小于当前树的值时才返回true,因此我可以给temp赋任意值。

bool isValidBST(TreeNode* root) {TreeNode* p = root;stack<TreeNode*> s;int temp = 233333;  // 随便设置的,无意义bool isTempUpdate = false;while (p != NULL || !s.empty()){while (p != NULL){s.push(p);p = p->left;}if (!s.empty()){p = s.top();if (isTempUpdate && temp >= p->val) return false;temp = p->val;isTempUpdate = true;s.pop();p = p->right;}}return true;
}

其它解法1:非递归的中序遍历,用LONG_MIN规避树的val等于INT_MIN的情况

代码见下:

bool isValidBST(TreeNode* root) {TreeNode* p = root;stack<TreeNode*> s;long temp = LONG_MIN;while (p != NULL || !s.empty()){while (p != NULL){s.push(p);p = p->left;}if (!s.empty()){p = s.top();if (temp >= p->val) return false;temp = p->val;s.pop();p = p->right;}}return true;
}

发现执行时间并没有缩短,反而内存占用多了一点点。。。

其他解法2:递归的中序遍历思想

首先,运用递归的中序遍历思想,递归的中序遍历代码如下:

void inorder(TreeNode *root, vector<int> &path)
{if (root != NULL){inorder(root->left, path);path.push_back(root->val);inorder(root->right, path);}
}

然后遍历比较vector里的元素即可,完整代码如下:

bool isValidBST(TreeNode* root) {vector<int> path;inorder(root, path);if (path.empty()) return true;for (int i = 0; i < path.size() - 1; i++){if (path[i] >= path[i + 1]) return false;}return true;
}void inorder(TreeNode* root, vector<int> &path) {if (!root) return;inorder(root->left, path);path.push_back(root->val);inorder(root->right, path);
}

其它解法3:即时比较的递归中序遍历

这个解法跟上个解法类似,不同之处在于这个解法没有用vector,而是在递归函数中进行比较的。
大概原理是基于递归的中序遍历,然后在函数中的两次递归调用都加一次返回。inorder(root->left, pre)是仅为false时才返回,如果是true就继续执行后续判断;inorder(root->right, pre)是在函数的最后,无论true还是false均要返回。除了这两处递归调用要返回,还有函数本身要返回的地方就是比较pre->val 和此时输入参数root的val大小,返回 true或者 false。

bool isValidBST(TreeNode* root) {TreeNode* pre = NULL;return inorder(root, pre);
}bool inorder(TreeNode* root, TreeNode* &pre)
{if (!root) return true;bool res = inorder(root->left, pre);if (!res) return false;if (pre){if (pre->val >= root->val) return false;}pre = root;return inorder(root->right, pre);
}

其它解法4:节点继承法

这题实际上简化了难度,因为有的时候题目中的二叉搜索树会定义为左<=根<右,而这道题设定为一般情况左<根<右,那么就可以用中序遍历来做。因为如果不去掉左=根这个条件的话,那么下边两个数用中序遍历无法区分:

    1         1/           \    1             1

因此,可以采用我自己命名的节点继承法(只是命名,不是我的方法233333),能够区分出来是左节点还是右节点的情况,代码如下:

bool isValidBST(TreeNode* root) {return isValidBST(root, LONG_MIN, LONG_MAX);
}bool isValidBST(TreeNode* root, long mn, long mx) {if (!root) return true;if (root->val <= mn || root->val >= mx) return false;return isValidBST(root->left, mn, root->val) && isValidBST(root->right, root->val, mx);
}

不太好理解,可以这样想:我为什么称之为节点继承法,就是因为每个节点的值都要跟两个值比较,大值和小值,每一次的递归都要保证当前节点的val大于大值,小于小值。而大值和小值都是继承自上一个节点所用到的大值或小值,即递归函数的第二个和第三个参数。
举一个例子,比如有这样一个树:

                                 5/ \3   8/ \2   9

首先,看值为5的节点,它上面没有父节点,因此mn和mx分别设置为LONG_MIN和LONG_MAX即可,然后进入下一层递归,先是左节点root(3)要小于父节点的值,因此第二个参数mn设置为父节点的val,即root(5)->val。而对于第三个参数mx,要保证值为3的这个节点小于它,直接继承下来上一次递归所用的第三个参数,意思是3虽然要小于5,但是也要大于root(5)的左父节点(左父节点不存在,就用LONG_MIN)。
如果还不理解,可以继续往下看,进入下一层递归,直接看root(9),递归函数所用的第一个参数是root(3)->right,第三个参数是root(3)->val,这没什么问题。再看第二个参数,直接继承的上一次递归,也就是判断3节点是用的第二个参数root(5)->val,意思是root(3)->val要小于root(5)->val,其后所有子节点都要小于root(5)->val。
总结下来,就是父节点所要大于或小于的东西,子节点也要满足,可以理解为继承关系。还拿root(9)来说,它首先继承了root(3)节点,要大于root(3)大于的LONG_MIN,也要小于root(3)小于的root(5)->val,继承完再看它自己的新条件,因为root(3)是root(9)的左父节点,因此root(9)->val要大于root(3)->val。

Leetcode 98:验证二叉搜索树相关推荐

  1. LeetCode 98. 验证二叉搜索树(中序遍历)

    文章目录 1. 题目信息 2. 解题 2.1 递归中序 2.2 非递归中序 1. 题目信息 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于 ...

  2. leetcode —— 98. 验证二叉搜索树

    给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也是二叉搜索 ...

  3. LeetCode 98 验证二叉搜索树

    题目链接:力扣 思路 递归 递归函数声明 bool isValidBST(TreeNode* root,int lower,int upper);//判断根节点是否在lower和upper之间 递归出 ...

  4. leetcode 98. 验证二叉搜索树 递归遍历左右子树和中序遍历 c语言解法

    如题: 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也是 ...

  5. Leetcode 98. 验证二叉搜索树 (每日一题 20210810)

    给定一个二叉树,判断其是否是一个有效的二叉搜索树.假设一个二叉搜索树具有如下特征:节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也是二叉搜索树. ...

  6. LeetCode 98. 验证二叉搜索树 思考分析

    题目 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也是二 ...

  7. leetcode - 98. 验证二叉搜索树

    给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也是二叉搜索 ...

  8. LeetCode 98. 验证二叉搜索树(递归)(迭代)

    题目描述 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也 ...

  9. Leetcode 98. 验证二叉搜索树 解题思路及C++实现

    解题思路: 分别验证root的左右子树是否是二叉树,同时,左子树的最大值要小于root->val,右子树的最小值要大于root->val. 在左右子树中,一直向root的左子树探索,就能得 ...

最新文章

  1. 如何卸载Exchange Server 2010
  2. Jdon框架开发指南
  3. Java 多线程断点下载文件_详解
  4. python基础-第三篇-函数编程
  5. 云主机安装linux发行版,用Ubuntu服务器版部署一个私有云
  6. java怎么通过字段去获取对象_通过java反射获取任意对象的字段名及字段值
  7. editorMd插件的使用总结(包括开启图片上传及拖拉粘贴上传图片)
  8. Acwing算法提高课—搜索
  9. rhel6.5 oracle12c,中标麒麟Linux6.5安装Oracle12C配置过程
  10. HBuilder升级失败,/HBuilder/plugins 被另—个程序占用,请退出占用程序或者重启计算机后重试
  11. leetcode1438
  12. Python之父-Guido van Rossum
  13. Excel函数(五)- 超有用的count系列函数count、counta、countif、countifs
  14. 新手尝试编写微信小程序(1)——我的第一个微信小程序
  15. Vue中实现文字向上滚动的动画效果
  16. 《中级数据库系统工程师》
  17. 同程艺龙小程序性能监控系统的探索与实践
  18. 深度学习——NiN网络模型(笔记)
  19. 有孚网络副总裁吕鑫:合纵连横,云领未来—如何打造低成本混合云架构
  20. gdb optimized out

热门文章

  1. 不买NAS搭建私有云盘:设定群晖共享文件夹并安装cpolar 4-5
  2. SEO文章伪原创在线生成PHP源码
  3. 02325计算机系统结构202010,2019年10月自考计算机系统结构02325真题
  4. Apache部署PHP项目(最完整详细的Apache+PHP项目根目录部署)
  5. 最高法:侵犯公民个人信息犯罪案件数量显著增长
  6. 心态决定命运(别让心态毁了你自己)
  7. 阿里云部署docker项目流程
  8. 4S店的金融服务费,并不全是在坑你
  9. unit 10 文档练习
  10. java8 jce无限制权,JDK JCE 限制和无限制