题目描述
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
- 节点的左子树只包含小于当前节点的数。
- 节点的右子树只包含大于当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
解题思路
二叉搜索树是递归定义的,所以也可以递归验证。(cf:《剑指offer》第55题,验证平衡二叉树,书上的“后序遍历”验证法代码不好,参考博客)
这个题不要以为简单:乍一看,以为这是一个平凡的问题。只需要遍历整棵树,检查 node->right->val > node->val
和node->left->val < node->val
对每个结点是否成立。**这是不对的!!!**因为不仅右子结点要大于该节点,整个右子树的元素都应该大于该节点(这是个坑,错过一次了)。如下:
10
/ \
5 15
/ \
6 20
这意味着我们需要在遍历树的同时保留结点的上界与下界,在比较时不仅比较子结点的值,也要与上下界比较。主要有两种方法:
-
递归法:通过限定每个节点值的范围来验证二叉搜索树。(题解)
- 遍历节点root时,给出root值的范围 ( m i n v , m a x v ) (minv,maxv) (minv,maxv), m i n v < r o o t . v a l < m a x v minv < root.val < maxv minv<root.val<maxv,当 r o o t . v a l root.val root.val超出 范围 ( m i n v , m a x v ) (minv,maxv) (minv,maxv) 时,就不算二叉搜索树了。
- 递归左子树时,左子树的最大值不能超过 r o o t . v a l root.val root.val。
- 递归左子树时,右子树的最小值不能小于 r o o t . v a l root.val root.val。
class Solution { public: bool isValidBST(TreeNode* root) { if(root == nullptr) return true; return verifyRecursively(root, LONG_MIN, LONG_MAX); } bool verifyRecursively(TreeNode* pNode, long left_min, long right_max){ if(pNode == nullptr) return true; if(pNode->val <= left_min || pNode->val >= right_max) return false; return verifyRecursively(pNode->left, left_min, pNode->val) && verifyRecursively(pNode->right, pNode->val, right_max); } };
-
中序遍历法:因为二叉搜索树中序遍历是递增的,所以我们可以中序遍历判断前一数是否小于后一个数。(评论板块)
参考代码
上面给出了“利用最大值最小值”的解法,下面是利用“中序遍历”的解法。
class Solution {
public:
TreeNode* pre;
bool isValidBST(TreeNode* root) {
//方法一 非递归
stack<TreeNode*> s;
TreeNode* cur = root;
while(!s.empty() || cur){
if(cur){
s.push(cur);
cur = cur->left;
}else{
cur = s.top();
s.pop();
if(pre && pre->val >= cur->val) return false;
pre = cur;
cur = cur->right;
}
}
return true;
//方法二 递归
if(root == NULL)
return true;
if(!isValidBST(root->left))
return false;
if(pre && pre->val >= root->val)
return false;
pre = root;
if(!isValidBST(root->right))
return false;
return true;
}
};
完整的“中序遍历”递归代码
class Solution {
public:
bool isValidBST(TreeNode* root) {
// 递归出口,注意空树也是二叉搜索树
if(root == nullptr)
return true;
bool left = isValidBST(root->left);
if(pPre && pPre->val >= root->val)
return false;
pPre = root;
bool right = isValidBST(root->right);
return left && right;
}
private:
TreeNode* pPre = nullptr;
};