leetcode 链接:合法二叉搜索树
《程序员面试代码指南》by 左程云 中相关题目:★★☆☆找到二叉树中的最大搜索二叉树(树形dp套路)
题目
实现一个函数,检查一棵二叉树是否为二叉搜索树。
示例:
输入: [2,1,3]2/ \1 3输出: true
输入: [5,1,4,null,null,3,6]5/ \1 4/ \3 6输出: false解释: 输入为: [5,1,4,null,null,3,6]。根节点的值为 5 ,但是其右子节点值为 4 。
注意如下特殊情形:
输入: [1,1]1/1输出: false
输入: [2147483647]2147483647输出: true
输入: [-2147483648]-2147483648输出: true
解答 & 代码
解法一:
想法:如果以
root节点为根节点的树是二叉搜索树,那么要求它的左子树是二叉搜索树、右子树是二叉搜索树,且左子树的最大值小于root的值,右子树的最小值大于root的值
设置一个 ReturnType 结构作为返回的结构,得到以 root 节点为根节点的树的一些信息,里面包含以 root 节点为根节点的树中的最小节点值 minVal、最大节点值 maxVal 以及该树是否为二叉搜索树 isBST 
设置 ReturnType posOrderProcess(TreeNode* root) 函数,进行递归 后序遍历,以得到以 root 节点为根节点的树中的最小节点值 minVal、最大节点值 maxVal 以及该树是否为二叉搜索树 isBST :
- 递归结束条件:root 为 NULL,则返回 
ReturnType(minVal=(long long)INT_MAX + 1, maxVal=(long long)INT_MIN - 1, isBST=true) - 递归得到 
root左子树的信息 - 递归得到 
root右子树的信息 - 计算以 
root节点为根节点的树中的最小的节点值:比较左子树的的最小值、右子树的最小值和root的值 - 计算以 
root节点为根节点的树中的最大的节点值:比较左子树的的最大值、右子树的最大值和root的值 - 如果左子树的最大值小于 
root的值,且右子树的最大值大于root的值,且左子树是二叉搜索树,且右子树是二叉搜索树,那么以root节点为根节点的树是二叉搜索树,返回其信息 - 否则,以 
root节点为根节点的树不是二叉搜索树,返回其信息 
注意:本题有几个需要额外关注的输入样例
输入: [2147483647],输出 true:INT_MAX = 2147483647,因此在递归结束条件中,不能将返回值的minVal设为INT_MAX,否则回到上层递归比较,发现右子树的最小值(INT_MAX)等于root的值(2147483647),于是错误判定这棵树不是二叉搜索树- 并且不能直接将判定条件改成小于等于:“如果左子树的最大值小于等于 
root的值,且右子树的最大值大于等于root的值,且左子树是二叉搜索树,且右子树是二叉搜索树,那么以root节点为根节点的树是二叉搜索树”,因为还有输入为 [1, 1] 的情况,答案判定为false,也就是说该题还要求左子树的值严格小于root的值,且严格小于右子树的值,而不能相等 
- 并且不能直接将判定条件改成小于等于:“如果左子树的最大值小于等于 
 输入: [-2147483648],输出 true:INT_MIN = -2147483648,和上面类似,在递归结束条件中,不能将返回值的maxVal设为INT_MIN,否则回到上层递归比较,发现左子树的最大值(INT_MIN)等于root的值(-2147483648),于是错误判定这棵树不是二叉搜索树输入: [1,1],输出 false:也就是要求左子树的值严格小于root的值,且严格小于右子树的值,而不能相等,才算二叉搜索树
解决方法:将 int 改为 long long(不能是 long,long 的取值范围和 int 相同);且在递归结束条件中,将返回值的 minVal 设为 INT_MAX + 1 ,将返回值的 maxVal 设为 INT_MIN - 1
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/struct ReturnType {long long minVal;long long maxVal;bool isBST;ReturnType(long minV, long maxV, bool BST): minVal(minV), maxVal(maxV), isBST(BST) {}};class Solution {private:ReturnType posOrderProcess(TreeNode* root) {if(root == NULL)return ReturnType((long long)INT_MAX + 1, (long long)INT_MIN - 1, true);ReturnType lData = posOrderProcess(root->left);ReturnType rData = posOrderProcess(root->right);long long minVal = (lData.minVal < rData.minVal) ? lData.minVal : rData.minVal;minVal = (minVal < root->val) ? minVal : root->val;long long maxVal = (lData.maxVal > rData.maxVal) ? lData.maxVal : rData.maxVal;maxVal = (maxVal > root->val) ? maxVal : root->val;if(lData.isBST && rData.isBST && lData.maxVal < root->val && rData.minVal > root->val)return ReturnType(minVal, maxVal, true);elsereturn ReturnType(minVal, maxVal, false);}public:bool isValidBST(TreeNode* root) {return posOrderProcess(root).isBST;}};
执行结果:
执行结果:通过
执行用时:12 ms, 在所有 C++ 提交中击败了 85.77% 的用户
内存消耗:21.2 MB, 在所有 C++ 提交中击败了 13.79% 的用户
解法二:
以 root 节点为根的树是二叉搜索树,只有几种情形:
root == NULLroot节点不为 NULL,左子树若不为空则左子树的值都小于root的值;右子树若不为空则右子树的值都大于root的值
思想:递归遍历每个节点的同时,缩小每个节点的值应满足的上下界,如果是二叉搜索树,就必须每个值都在其上下界内
因此,设置一个辅助的递归函数 bool isBST(TreeNode* root, long long min, long long max) 来判断以 root 节点为根的树是否为二叉搜索树
- 如果 
root == NULL,则是二叉搜索树,直接返回 true - 否则,需要先判断 
root的值是否在区间(min, max)内,注意是开区间,min、max分别是root节点值(or 以root节点为根的树)的上下界- 如果不在区间内,则不是二叉搜索树,返回 false
 - 如果在区间内,还需要继续缩小区间范围,递归判定其左子树的值是否在新的区间  
(min, root->val)内,以及其右子树的值是否在新的区间(root->val, max)内,如果满足条件,则是二叉搜索树,返回 true;否则不是二叉搜索树,返回 false
执行结果: ``` 执行结果:通过/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { private: bool isBST(TreeNode* root, long long min, long long max) { return (root == NULL) || ((root->val > min) && (root->val < max) && isBST(root->left, min, root->val) && isBST(root->right, root->val, max)); } public: bool isValidBST(TreeNode* root) { return isBST(root, LONG_MIN, LONG_MAX); } }; 
 
执行用时:16 ms, 在所有 C++ 提交中击败了 61.73% 的用户 内存消耗:21 MB, 在所有 C++ 提交中击败了 58.78% 的用户 ```
