问题描述
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
有效二叉树的特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
思考过程
容易想到的就是用递归进行判断,出现不满足的情况就返回false,否则就以相同的方式继续检查左子树和右子树。由此写出的代码:
/**
* 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 temp=true;
bool isValidBST(TreeNode* root) {
if(root==nullptr)
return true;
if(root->left!=nullptr ){
if((root->left->val) >= (root->val))
temp=false;
else
temp=isValidBST(root->left);
}
if(root->right!=nullptr ){
if((root->right->val) <= (root->val))
temp=false;
else
temp=isValidBST(root->right);
}
return temp;
}
};
但是提交之后报错,才发现我忽略了一种情况。
树结构可视化:
如上数值为3的节点,它满足了小于6,但是却没有满足大于5,因此应该返回false。但上述代码并不能实现。
发现错误之后我尝试了多种解决方案,比如类似人工智能里最大最小树用α-β算法进行剪枝,我引入了两个全局变量进行比较,但是发现并不能用简单的左右子树来区分当前节点值应该小于或大于α-β的值;然后又用一个全局变量tempval来实现,但是又出现了当递归向前返回时tempval不会恢复之前的值的问题。
磨了几个小时,最终还是看了题解…
题解
递归
官方题解用的递归函数同时还传进去了一个范围,若节点的值不在此范围内则返回false,否则更新范围并继续在左右子树中进行判断。
class Solution {
public:
bool isValid(TreeNode* root,long long int min_val,long long int max_val){
if(root==nullptr)
return true;
if(root->val <= min_val || root->val >= max_val)
return false;
return isValid(root->left,min_val,root->val) && isValid(root->right,root->val,max_val);
}
bool isValidBST(TreeNode* root) {
return isValid(root,LONG_MIN, LONG_MAX);
}
};
时间复杂度:O(n)
空间复杂度:O(n)
中序遍历
如果能想到“一棵二叉树若满足题目所述性质,则其中序遍历结果是按从小到大排序的数集”的话,这题就变得简单了——进行中序遍历并检查后一个节点的值是否大于前一个节点的值,若是则继续遍历,否则返回false。
官方是用栈的方式实现中序遍历:
class Solution {
public:
bool isValidBST(TreeNode* root) {
stack<TreeNode*> stack;
long long inorder = (long long)INT_MIN - 1;
while (!stack.empty() || root != nullptr) {
while (root != nullptr) {
stack.push(root);
root = root -> left;
}
root = stack.top();
stack.pop();
if (root -> val <= inorder) {
return false;
}
inorder = root -> val;
root = root -> right;
}
return true;
}
};
也可以用递归的方式实现中序遍历:
class Solution {
public:
long long temp_val=LONG_MIN;
bool res=true;
bool isValidBST(TreeNode* root) {
if(res==false)
return res;
if(root==nullptr)
return true;
isValidBST(root->left);
if(root->val<=temp_val)
res = false;
temp_val=root->val;
isValidBST(root->right);
return res;
}
};
时间复杂度:O(n)
空间复杂度:O(n)
不过从实际运行结果来看,中序遍历的方法无论是从时间上还是空间上都没有递归的方式优。
心得
坚信量变引起质变的第三天,冲!