98. Validate Binary Search Tree
Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
The left subtree of a node contains only nodes with keys less than the node's key.
The right subtree of a node contains only nodes with keys greater than the node's key.
Both the left and right subtrees must also be binary search trees.
Example 1:
2
/ \
1 3
Binary tree [2,1,3], return true.
Example 2:
1
/ \
2 3
BST顺序遍历的结果是一个递增的数组,因此,在遍历每一个子树的时候,子树的值会有一定的范围
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
//这里采用的long型,为了防止验证INT_MAX时出现错误
class Solution {
public:
bool isValidBST(TreeNode* root) {
return validate(root, LONG_MIN, LONG_MAX);
}
private:
bool validate(TreeNode *r, long min, long max){
if(r == NULL) return true;
return min<r->val && r->val < max && validate(r->left, min, r->val) && validate(r->right, r->val, max);
}
};
上面采用记录最大数值的方法,下面将采用某段区间上的最大节点,最小节点的方法
class Solution {
public:
bool isValidBST(TreeNode* root) {
return validate(root, NULL, NULL);
}
private:
bool validate(TreeNode *r, TreeNode *minNode, TreeNode *maxNode){
if(r == NULL) return true;
if(minNode && minNode->val >= r->val || maxNode && r->val >= maxNode->val ) return false;
return validate(r->left, minNode, r) && validate(r->right, r, maxNode);
}
};
下面的方法比较巧妙。
5
/ \
3 6
/ \
1 4
在保证二叉搜索树性质的时候,最重要的是要保证根节点的左子树中的前驱节点(根节点),prev就是用来记录这个节点的。
上述递归的过程为,
validate(5, prev)(此时prev == NULL)
(1) / \(4)
/ \
validate(3, prev)(prev == NULL)
(2) / \(3)
/ \
validate(1, prev) validate(4, prev)
递归的运行过程为:
(1) ->(2)从(1)到(2)的过程中,prev始终为NULL;此时到达valiate(1, prev),接着遍历1的左节点,为空,返回true。此时prev为空,r为1。接下来的过程prev就变成了r,r就是r右子树的前驱。递归返回到validate(3, prev)中的后半部分,
我们会发现prev走过的节点的过程就是一个中序遍历走的节点的过程
NULL ---> 1 --->3 --->4 --->5
class Solution {
public:
bool isValidBST(TreeNode* root) {
TreeNode *p = NULL;
return validate(root, p);
}
private:
//prev记录的是前驱节点
bool validate(TreeNode *r, TreeNode * & prev){
if(r == NULL) return true;
if(!validate(r->left, prev)) return false;
//在每次遍历子树的右半边的时候,总能将prev更新到根节点的前驱节点
if(prev && prev->val >= r->val) return false;
prev = r;
return validate(r->right, prev);
}
};