QUESTION
medium
题目描述
给定一个二叉树,判断其是否是一个有效的二叉搜索树
假设一个二叉搜索树具有如下特征:
- 节点的左子树只包含小于当前节点的数
- 节点的右子树只包含大于当前节点的数
- 所有左子树和右子树自身必须也是二叉搜索树
示例 1:
输入:
2
/ \
1 3
输出: true
示例 2:
输入:
5
/ \
1 4
/ \
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6],根节点的值为 5 ,但是其右子节点值为 4
说明
无
SOLUTION
一看到这个题目,第一反应的直接递归判断,使得该结点的键值大于所有左结点的键值,小于所有右结点的键值,这个办法似乎有点麻烦,而且总是感觉有些难以理解,有没有别的办法呢
方法一
按照前面的想法,从根递归下去,判断值,注意要更新每个子树的上下限
bool isValidBST(TreeNode* root) {
return isValid(root, LONG_MIN, LONG_MAX);
}
bool isValid(TreeNode *root, long mn, long mx) {
if(!root) return true;
if(root->val <= mn || root->val >= mx) return false;
return isValid(root->left, mn, root->val) && isValid(root->right, root->val, mx);
}
方法二(BST中序遍历的性质)
明白一个简单的结论:BST
的中序遍历是严格递增的
bool isValidBST(TreeNode* root) {
if(!root) return true;
vector<int> in;
inorder(root, in);
if(in.size() == 1) return true;
else {
for (int i = 0; i < in.size() - 1; i++)
if (in[i] >= in[i+1]) return false;
return true;
}
}
void inorder(TreeNode *root, vector<int> &in) {
if (!root) return;
inorder(root->left, in);
in.push_back(root->val);
inorder(root->right, in);
}
这个方法,其实还可以简化,可以不用数组保存,实际上可以在遍历的同时检查是否严格递增,下面这段代码是copy了别人的写法,确实太厉害了(原文:http://www.cnblogs.com/grandyang/p/4297300.html)
bool isValidBST(TreeNode* root) {
TreeNode* pre = NULL;
return isValid(root, pre);
}
bool isValid(TreeNode* node, TreeNode*& pre){
if(!node) return true;
bool left = isValid(node->left, pre);
if(!left) return false;
if(pre && node->val <= pre->val) return false;
pre = node;
return isValid(node->right, pre);
}
当然既然是中序遍历,那也有不是递归的写法
bool isValidBST(TreeNode* root) {
stack<TreeNode*> s;
TreeNode *p = root, *pre = NULL;
while (p || !s.empty()) {
while (p) {
s.push(p);
p = p->left;
}
p = s.top(); s.pop();
if (pre && p->val <= pre->val) return false;
pre = p;
p = p->right;
}
return true;
}
上面原文的大佬解释中有非递归非栈的写法,有兴趣的的小伙伴,可以移步围观