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數據可能會溢出,看成開區間
}
};
結果: