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.
基本问题,判定二叉查找树是否成立。注意binary tree,二叉树,只是形状上有要求,只有二叉查找树,也就是这里的BST,才有我们通常意义上的左小右大性质。这里的验证第一反应就是递归啊,每一次递归要求左子树小于根,右子树大于根。但注意,这只是局部的要求,整体上还得保持一致,还得保持跟之前的节点间的大小关系。所以我们递归函数不仅传递节点,还传递合理的动态范围。
方法一:divide and conquer
bool isValidBST(TreeNode* root) {
return helper(root, INT_MIN, INT_MAX);
}
bool helper (TreeNode* t, int val_min, int val_max) {
if (t == NULL) return true;
if (t->val >= val_min && t->val <= val_max) {
if (t->left != NULL) {
if (val_min == t->val) return false;//避免二者都是INT_MIN
if (!helper(t->left, val_min, t->val-1)) return false;
}
if (t->right != NULL) {
if (val_max == t->val) return false;//避免二者都是INT_MAX
if (!helper(t->right, t->val+1, val_max)) return false;
}
return true;
}
return false;
}
其实这里的递归很好解决,需要注意的问题是动态范围的范围问题,因为测试用例里出现了很多INT的最大最小值。所以我们采用了闭区间作为范围,保证了可以等于INT_MAX, INT_MIN, 然后传递新的动态范围的时候提前做了预判,如果两者都等于MAX或者MIN,加一减一都失效,所以提前判断下。
方法二:中序遍历二叉树inorder traverse
因为二叉查找树中序遍历后输出应该是升序序列,所以可以从这一点上遍历BST来检查。
version 1:
bool isValidBST(TreeNode *root) {
vector<int> res;
printTree(root, res);
for (int i = 1; i < res.size(); i++) {
if (res[i] <= res[i-1]) return false;
}
return true;
}
void printTree (TreeNode *t, vector<int>& res) {
if (t == NULL) return;
if (t->left != NULL) printTree(t->left, res);
res.push_back(t->val);
if (t->right != NULL) printTree(t->right, res);
}
输出到int型数组里,再遍历数组。省去了数据类型的边界问题。
当然,也没有必要非要这么实在的把所有值存好,可以更进一步省去内存消耗。
version 2:
class Solution {
private:
TreeNode *lastNode = NULL;
public:
bool isValidBST(TreeNode *root) {
if (root == NULL) return true;
if (!isValidBST(root->left)) return false;
if (lastNode != NULL && lastNode->val >= root->val) return false;
lastNode = root;
return (isValidBST(root->right));
}
};
用一个lastNode贯穿始终,因为我们只需要判断是否是严格的升序序列就行。