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:
Input:
2
/ \
1 3
Output: true
Example 2:
5
/ \
1 4
/ \
3 6
Output: false
Explanation: The input is: [5,1,4,null,null,3,6]. The root node’s value is 5 but its right child’s value is 4.
思路:二叉搜索树就是左子树中的节点比根节点小,右子树中节点值比根节点大。看到和树相关的题目很自然会想到递归的做法。根据二叉搜索树的性质,可以递归地判断当前节点作为根节点其左孩子是否比根节点小,并且其右孩子是否比根节点大。 于是可以写出如下的程序。
class Solution(object):
def isValidBST(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
return self.validBST(root)
def validBST(self, root):
if root == None:
return True
leftNode = root.left
rightNode = root.right
if leftNode and leftNode.val >= root.val:
return False
if rightNode and rightNode.val <= root.val:
return False
return self.validBST(leftNode) and self.validBST(rightNode)
但是你会看到:
这里这个6虽然小于15,但是6比根节点10小。而二叉搜索树的所有右子树应该比根节点大。所以上面这种只判断一个由3个节点构成的子树是否符合二叉搜索树的性质是不行的,只考虑了局部,没有考察整体。
上面的思路行不通,我们必须换一个思路。其实从上面的比较中发现,二叉搜索树其实可以看成一个节点的数值是否在某个区间内。所以我们转换思路。首先根节点的范围没有限制,只要在正负无穷之间即可,而其左子树应该比根节点的值小,所以左子树属于的区间应该小于根节点的值;右子树应该比根节点的值大,所以右子树属于的区间应该大于根节点的值。 一个例子如下图,可以看到节点6不属于区间(10, 15)
,所以这棵树不是二叉搜索树。
上面思路的python实现:
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def isValidBST(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
return self.validBST(root, -float('inf'), float('inf'))
def validBST(self, root, left, right):
if root == None:
return True
leftNode = root.left
rightNode = root.right
rootVal = root.val
if rootVal<=left or rootVal>=right:
return False
return self.validBST(leftNode, left, rootVal) and self.validBST(rightNode, rootVal, right)
结果:
c++实现:
不得不提一下,如果你自己用c++尝试了这题,应该会发现这题很多数据点设计的很巧妙,很多地方会涉及无穷大无穷小,一不小心容易造成溢出。python中可以用float('inf')
表示无穷大,-float('inf')
表示无穷小,而c++中并没有绝对的无穷大,刚好这题节点的数值只是int类型,所以不能用INT_MAX
和INT_MIN
,而换成INT64_MAX
,INT64_MIN
即可。上面这种做法在数据能达到INT64_MAX
和INT64_MIN
时就不行了。后面我自己写了个重载运算符来间接实现无穷大无穷小,有些麻烦,不过能做出来,而且数据更大应该也没问题。
/**
* 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 {
public:
bool binaryTree = true;
bool isValidBST(TreeNode* root) {
validBST(root, INT64_MIN, INT64_MAX);//INT64_MIN, INT64_MAX
return binaryTree;
}
void validBST(TreeNode* root, long left, long right){//long
if(root == NULL)
return;
TreeNode* leftNode = root->left;
TreeNode* rightNode = root->right;
if(root->val<=left || root->val>=right)//看成开区间
{
binaryTree = false;
return;
}
validBST(leftNode, left, root->val);//如果是int 不能减一root-val-1
validBST(rightNode, root->val, right);//如果是int 不能加一root->val+1数据可能会溢出
}
};
结果
另一个版本,有点复杂,但是适用性更强,上面的方法对这题已经OK。有兴趣可以看看,个人能力有限,欢迎提出更简单的方法。。。
class Myint{
public:
Myint(int type, int val = 0){
this->type = type;
this->val = val;
}
bool operator<=(int val){
if(type == 1)//无穷大
{
return false;//无穷大不比任何数小
}
else if(type == 0){
return true;//无穷小比任何数小
}
else{
return this->val<=val;//此时Myint表示一个普通整数
}
}
bool operator<=(Myint myint){
if(type == 1)//无穷大
{
return false;//无穷大不比任何数小
}
else if(type == 0){
return true;
}
else{
return this->val<=myint.getVal();
}
}
bool operator>=(int val){
if(type == 1){
return true;//无穷大比任何数大
}
else if(type == 0){
return false;//无穷小比任何数小
}
else{
return this->val>=val;
}
}
bool operator>=(Myint myint){
if(type == 1){
return true;//无穷大比任何数大
}
else if(type == 0){
return false;//无穷小比任何数小
}
else{
return this->val>=myint.getVal();
}
}
int getVal(){
return val;
}
private:
int type;
int val;
};
class Solution {
public:
bool binaryTree = true;
bool isValidBST(TreeNode* root) {
Myint myMax(1);//表示无穷大无穷小第二个参数不用赋值,没有用到
Myint myMin(0);
if(root && root->left==NULL && root->right==NULL)//只有根节点
{
binaryTree = true;
return binaryTree;
}
validBST(root, myMin, myMax);
return binaryTree;
}
void validBST(TreeNode* root, Myint left, Myint right){
if(root == NULL)
return;
TreeNode* leftNode = root->left;
TreeNode* rightNode = root->right;
if(left>=root->val || right<=root->val)//看成开区间
{
binaryTree = false;
return;
}
Myint rootVal(2, root->val);
validBST(leftNode, left, rootVal);//不能减一root-val-1
validBST(rightNode, rootVal, right);//不能加一root->val+1数据可能会溢出,看成开区间
}
};
结果: