题目
题目链接:
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
-
节点的左子树只包含 小于 当前节点的数。
-
节点的右子树只包含 大于 当前节点的数。
-
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:root = [2,1,3]
输出:true
示例 2:
输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。
提示:
- 树中节点数目范围在[1, 104] 内
- -231 <= Node.val <= 231 - 1
解题思路
思路一(纯中序遍历):
看到二叉搜索树首先应该想到的是中序遍历,二叉搜索树的中序遍历是递增的,所以这题可以用这种方法做。
中序遍历解法里面可以有个小优化:直接在遍历的过程判断是否存在先遍历的节点大于后遍历的节点。如果存在,直接返回false。否则,返回true。这时,就需要一个变量存储已经遍历的节点值,去和每个遍历的节点值比较。
有个要注意的地方是变量不能开 int,因为 Node.val 的取值范围是int的所有范围,如果用int,在判断前一个遍历过的节点值 f 的是否大于等于当前值 val 的时候会出错。val 可能等于 int 的最小值,这样就直接返回false了。所以 f 应该赋于初值小于int型的最小值:LONG_MIN。当然你也可以不用这种写法,用一个容器/数组存储一下,后面遍历是否递增即可。
思路二:
根据二叉搜索树的特点:节点的左子树的所有节点的值必须小于该结点的值,右子树必须大于。可以使用在二叉查找树(二叉搜索树)中查找的方法,一个分支一个分支进行查找,不过此题是验证是否是二叉搜索树,所以需要每个分支都遍历到。
简单的说就是利用该子树的最小值和最大值,判断该子树的所有节点值是否在这个范围内。
代码
思路一代码:
class Solution {
public:
bool isValidBST(TreeNode* root) {
long long f = LONG_MIN; //这里不能开int
stack<TreeNode *> sta;
while (!sta.empty() || root) {
while (root) {
sta.push(root);
root = root->left;
}
TreeNode *p = sta.top();
sta.pop();
if (f >= p->val) {
return false;
}
f = p->val;
root = p->right;
}
return true;
}
};
//中序遍历递归法太简单,省略。。。
思路二代码:
public:
bool isture(TreeNode *root, long long min, long long max) {
if (!root)
return true;
if (root->val <= min || root->val >= max)
return false;
return isture(root->left, min, root->val) && isture(root->right, root->val, max);
}
bool isValidBST(TreeNode* root) {
return isture(root, LONG_MIN, LONG_MAX);
}
};
总结
此题主要考二叉搜索树的性质:中序遍历递增和当前节点大于左子树,小于右子树。
利用中序遍历解题的思路一不难想到,但思路二相比思路一要难想一点。题目整体来说不难。对于每个类型的最大最小值宏定义变量最好记住,一些边界和比较问题可能会用上。