这道题前几遍刷的时候,说实话都没有太搞清楚。导致有两个on site都栽在了这道题上,悔得肠子都青了。
首先来说最简单的解法。因为要验证的树是BST,那个当我们pre-order遍历的时候,得到的结果将会是一个升序数组。所以每访问到一节点,我们只用判断当前节点是不是大于上一个访问的节点的值就可以了。
需要注意的是,如果维护一个vector<int>保存所有之前访问过的节点的值,那么只用int类型的变量就能解决这个问题,代价就是引进了O(n)的空间复杂度。当然也有这种的办法,就是只用vector<int>的第一个元素记录pre的值,那个就不用担心初始化了。不过这个方法有点非主流。我就随便摘一种写一下,代表pre-order这一大类解法。
class Solution {
private:
long long pre=-100000000000;
public:
bool isValidBST(TreeNode* root) {
if(root==nullptr)
return true;
if(!isValidBST(root->left))
return false;
if(root->val<=pre)
return false;
else
pre=root->val;
if(!isValidBST(root->right))
return false;
return true;
}
};
第二种解法就是限制每一个subtree的上下界。这是比较普遍的一种做法。这种解法也有需要初始化上下界包含INT_MIN~INT_MAX的情况。我们还可以再多设置两个变量表示INT_MAX和INT_MIN是否出现过。
class Solution {
public:
bool isValidBST(TreeNode* root) {
return helper(root, INT_MIN, INT_MAX, false, false);
}
bool helper(TreeNode* root, int left_max, int right_min, int seen_min, int seen_max){
if(root==nullptr)
return true;
if(root->val==INT_MIN){
if(seen_min)
return false;
else
seen_min=true;
}
if(root->val==INT_MAX){
if(seen_max)
return false;
else
seen_max=true;
}
return ((left_max<root->val||(root->val==INT_MIN&&left_max==INT_MIN))&&
(right_min>root->val||(root->val==INT_MAX&&right_min==INT_MAX))&&
helper(root->left, left_max, root->val, seen_min, seen_max)&&
helper(root->right, root->val, right_min, seen_min, seen_max));
}
};
第三种解法我把他叫返回值法。就是每遍历一个subtree,都返回一个datadum表示这个subtree的特性。当前树的特性根据左子树datadum,右子树datadum和根节点整理完成。
class Datadum{
public:
long long min;
long long max;
bool valid;
Datadum(long long x, long long y, bool z){
min=x;
max=y;
valid=z;
}
};
class Solution {
public:
bool isValidBST(TreeNode* root) {
Datadum res=helper(root);
return res.valid;
}
Datadum helper(TreeNode* root){
if(root==nullptr){
return Datadum(2147483649, -2147483649, true);
}
Datadum left = helper(root->left);
Datadum right = helper(root->right);
if(left.valid==false||right.valid==false||
root->val<=left.max||root->val>=right.min){
return Datadum(-2147483649, 2147483649, false);
}
//cout<<root->val<<" "<<min(left.min, root->val)<<" "<<max(right.max,root->val)<<endl;
long long left_val=left.min<root->val?left.min:root->val;
long long right_val=right.max>root->val?right.max:root->val;
return Datadum(left_val, right_val, true);
}
};
这种做法的用时有点慢,对于这道题非常不推荐这种做法。但是搞明白这种解法,这道题的一些衍生题也就迎刃而解了。
比如 333 largest BST subtree 和最长连续子序列只需要对上文的返回值方法做一点点微小的修改。大致思路不变,在datadum种再添加一个参数就可以了。