Problem: 验证二叉搜索树
题目描述:
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
- 节点的左子树只包含小于当前节点的数。
- 节点的右子树只包含大于当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
Solution
对于二叉搜索树BST,在中序遍历的时候会得到单调递增的序列,注意这里是严格意义上的单调递增(不存在相等的情况),按照这一特点笔者想到的最直接的方法是:中序遍历收集节点的值,再遍历数组判断是否是单调递增即可。
中序遍历再判断
由于是树的遍历,笔者更倾向于使用递归方式:
class Solution {
public:
vector<int> ans;
void recur(TreeNode* root) {
if (root == nullptr)
return;
recur(root->left);
ans.push_back(root->val);
recur(root->right);
}
bool isValidBST(TreeNode* root) {
recur(root);
int n = ans.size();
for (int i = 1; i < n; ++i)
if (ans[i - 1] >= ans[i])
return false;
return true;
}
};
先序遍历
在尝试使用了中序遍历之后,另一种相近的方式:先序遍历同样也能够解决本题,在代码实现的过程中遇上了一些问题:
首先很顺理成章地写出了下面这一段codes:
class Solution {
public:
bool isValidBST(TreeNode* root) {
if (root == nullptr)
return false;
if (root->left && root->left->val >= root->val)
return false;
if (root->right && root->right->val <= root->val)
return false;
return isValidBST(root->left) && isValidBST(root->right);
}
};
写完之后成就感油然而生,然而在提交之后。。。。日常wrong answer。为什么会出错?在一番思索之后,我尝试了带入了一种情况,
错在了右子树中,在这里3并没有与5比较而仅仅与6完成了比较,上述代码只能进行局部判断:
像上图标注的这样,仅仅是对局部的三个节点进行了判断,很显然这是不全面的。那怎样才能进行完整的判断?
在递归函数中加入一个边界:最大值最小值,递归过程中不断更新边界。
class Solution {
public:
bool help(TreeNode* root, TreeNode* min, TreeNode* max) {
if (root == nullptr)
return true;
if (min && root->val <= min->val)
return false;
if (max && root->val >= max->val)
return false;
return help(root->left, min, root) && help(root->right, root, max);
}
bool isValidBST(TreeNode* root) {
return help(root, nullptr, nullptr);
}
};