- 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.
A single node tree is a BST
Example
Example 1:
Input: {-1}
Output:true
Explanation:
For the following binary tree(only one node):
-1
This is a binary search tree.
Example 2:
Input: {2,1,4,#,#,3,5}
Output: true
For the following binary tree:
2
/
1 4
/
3 5
This is a binary search tree.
解法1:
首先要注意的是BST的定义:
- root的值要大于所有左子树的节点的值,小于所有右子树节点的值。所以不能单单和左子节点与右子节点比较。
像下面这个代码就不会通过这个测试用例:
10,5,15,#,#,6,20
因为该例并非BST (10>6)。
bool isValidBST(TreeNode * root) {
if (!root)
return true;
if (root && !root->left && !root->right)
return true;
return isValidBST(root->left) &&
isValidBST(root->right) &&
(root->left ? root->val > root->left->val : true) &&
(root->right ? root->val < root->right->val : true);
}
- helper()函数会返回该root所代表的子树里面的最大值和最小值。左右子树的最大值和最小值都要考虑。
考虑 - min, max 还要考虑root本身的值。
- 下面链接有两个version值得好好研究。下次学习。
https://www.jiuzhang.com/solution/validate-binary-search-tree/#tag-highlight-lang-cpp
另外,这个链接关于LCA的讨论好像很不错,下次参考。
https://www.hrwhisper.me/algorithm-lowest-common-ancestor-of-a-binary-tree/
代码如下:
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: The root of binary tree.
* @return: True if the binary tree is BST, or false
*/
bool isValidBST(TreeNode * root) {
if (!root)
return true;
if (root && !root->left && !root->right)
return true;
ReturnType leftRet = helper(root->left);
ReturnType rightRet = helper(root->right);
return isValidBST(root->left) &&
isValidBST(root->right) &&
(root->left ? root->val > leftRet.max : true) &&
(root->right ? root->val < rightRet.min : true);
}
private:
struct ReturnType {
int max;
int min;
ReturnType(int a=INT_MIN, int b=INT_MAX) : max(a), min(b) {}
};
ReturnType helper(TreeNode* root) {
ReturnType ret;
if (!root)
return ret;
if (root && !root->left && !root->right)
return ReturnType(root->val, root->val);
ReturnType leftRet = helper(root->left);
ReturnType rightRet= helper(root->right);
ret.max = max(root->val, max(ret.max, max(leftRet.max, rightRet.max)));
ret.min = min(root->val, min(ret.min, min(leftRet.min, rightRet.min)));
return ret;
}
};
这个代码效率好像非常非常低,应该是做了很多无用计算。重新改写了一下,这个代码效率高很多。
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: The root of binary tree.
* @return: True if the binary tree is BST, or false
*/
bool isValidBST(TreeNode * root) {
if (!root)
return true;
if (root && !root->left && !root->right)
return true;
ReturnType ret = helper(root, LONG_MIN, LONG_MAX);
if (ret.valid)
return true;
else
return false;
}
private:
struct ReturnType {
long min;
long max;
bool valid;
ReturnType(long a=LONG_MIN, long b=LONG_MAX, bool c=true) : min(a), max(b), valid(c) {}
};
ReturnType helper(TreeNode* root, long min, long max) {
ReturnType ret;
if (!root)
return ret;
ReturnType leftRet = helper(root->left, min, (long)root->val);
ReturnType rightRet= helper(root->right, (long)root->val, max);
if (!leftRet.valid || !rightRet.valid || root->val <= min || root->val >= max)
return ReturnType(min, max, false);
return ReturnType(min, max, true);
}
};
解法3:
在构造一个BST时,一个左节点的值介于父亲子树的最小值和父亲值之间,一个右节点的值介于父亲值和父亲子树的最大值之间,才能继续向下构造。
更新:
每个节点都必须大于其左子树的最大值,小于其右子树的最小值,才算合格。
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: The root of binary tree.
* @return: True if the binary tree is BST, or false
*/
bool isValidBST(TreeNode * root) {
return helper(root, LONG_MIN, LONG_MAX);
}
private:
bool helper(TreeNode * root, long leftMax, long rightMin) {
if (!root) return true;
if (root->val <= leftMax|| root->val >= rightMin) return false;
return helper(root->left, leftMax, root->val) && helper(root->right, root->val, rightMin);
}
};
解法4:利用BST的InOrder遍历是递增序列这个特性。
class Solution {
public:
/**
* @param root: The root of binary tree.
* @return: True if the binary tree is BST, or false
*/
bool isValidBST(TreeNode * root) {
if (!root) return true;
inOrderTraversal(root);
int len = inOrderRes.size();
for (int i = 1; i < len; i++) {
if (inOrderRes[i] <= inOrderRes[i - 1]) return false;
}
return true;
}
private:
vector<int> inOrderRes;
void inOrderTraversal(TreeNode *root) {
if (!root) return;
inOrderTraversal(root->left);
inOrderRes.push_back(root->val);
inOrderTraversal(root->right);
}
};
代码同步在
https://github.com/luqian2017/Algorithm/
非递归的版本如下:
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: The root of binary tree.
* @return: True if the binary tree is BST, or false
*/
bool isValidBST(TreeNode * root) {
stack<TreeNode *> stk;
TreeNode *pre = nullptr;
while (!stk.empty() || root) {
while(root) {
stk.push(root);
root = root->left;
}
root = stk.top();
stk.pop();
if (pre && pre->val >= root->val) return false;
pre = root;
root = root->right;
}
return true;
}
};
5刷:
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
struct ResultType {
bool isValid;
long long maxVal;
long long minVal;
ResultType(bool isV, long long maxV, long long minV) : isValid(isV), maxVal(maxV), minVal(minV) {}
};
class Solution {
public:
/**
* @param root: The root of binary tree.
* @return: True if the binary tree is BST, or false
*/
bool isValidBST(TreeNode * root) {
return helper(root).isValid;
}
private:
ResultType helper(TreeNode *root) {
if (!root) {
return ResultType(true, LLONG_MIN, LLONG_MAX);//注意不能用INT_MIN和INT_MAX,不然如果节点值就是INT_MIN或INT_MAX会出错。
}
if (!root->left && !root->right) {
return ResultType(true, root->val, root->val);
}
ResultType left = helper(root->left);
if (!left.isValid) {
return ResultType(false, 0, 0);
}
ResultType right = helper(root->right);
if (!right.isValid) {
return ResultType(false, 0, 0);
}
if (root->val > left.maxVal && root->val < right.minVal) {
return ResultType(true, root->right ? right.maxVal : root->val, root->left ? left.minVal : root->val);
} //注意这里要加判断root->right和root->left是否存在的情况,不然的话,如果不存在,那么right.maxVal和left.minVal会用到LLONG_MIN和LLONG_MAX
return ResultType(false, 0, 0);
}
};
6刷:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isValidBST(TreeNode* root) {
return helper(root, NULL, NULL);
}
private:
bool helper(TreeNode *root, TreeNode *minNode, TreeNode *maxNode) {
if (!root) return true;
if (minNode) {
if (minNode->val >= root->val) return false;
}
if (maxNode) {
if (maxNode->val <= root->val) return false;
}
return helper(root->left, minNode, root) && helper(root->right, root, maxNode);
}
};
8刷:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isValidBST(TreeNode* root) {
if (!root) return true;
TreeNode *visited = new TreeNode(-1);
long long preV = (long long)INT_MIN - 1;
goLeft(root);
while (!stk.empty()) {
TreeNode *topNode = stk.top();
if ((!topNode->left || topNode->left == visited) && topNode->right != visited) {
//inorder code here
if ((long long)topNode->val <= preV) return false;
preV = (long long)topNode->val;
goLeft(topNode->right);
}
if (!topNode->right || topNode->right == visited) {
//postorder code here
visited = topNode;
stk.pop();
}
}
return true;
}
private:
stack<TreeNode *> stk;
void goLeft(TreeNode *root) {
while (root) {
//preorder code here
stk.push(root);
root = root->left;
}
return;
}
};