难度等级:中等
上一篇算法:
剑指 Offer 54. 二叉搜索树的第k大节点【37】
力扣此题地址:
98. 验证二叉搜索树 - 力扣(Leetcode)
1.题目:98. 验证二叉搜索树
给你一个二叉树的根节点 root
,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
- 节点的左子树只包含 小于 当前节点的数。
- 节点的右子树只包含 大于 当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
2.解题思路:
方式一:中序遍历
由中序遍历的访问特点“左节点 -> 根节点 -> 右节点”,再根据二叉搜索树的特点“左节点的值 < 当前结点的值 < 右节点的值”,我们可以利用这两个特性得出:
我们在中序遍历的时候实时检查当前结点的值是否大于前一个中序遍历到的结点的值即可。因为按照“左 -> 根 -> 右”的顺序遍历,刚好结点间的值是从小到大排序的。
所以,如果均大于则说明这个序列是升序的,整棵树是二叉搜索树,否则不是。
方式二:递归
由二叉搜索树的特点得出“左子树均小于根节点,右子树均大于根节点,左右子树同理”。
由这个启示我们可以设计一个递归函数 helper(root,lower,upper)来递归判断,root为当前结点,lower为最小值边界,upper为最大值边界,也就是当前结点要大于lower&&小于upper。
根据二叉搜索树的性质:
在递归调用左子树的时候,把上界upper改为root.val,即调用helper(root.left,lower,root.val),因为左子树里所有节点的值均小于它的根节点值。
在递归调用右子树的时候,把下界lower改为root.val,即调用helper(root.right,root.val,upper),因为右子树里所有节点的值均大于它的根节点值。
函数递归调用的入口为helper(root,-inf,+inf),inf表示long类型的最大值
思路参考:
98. 验证二叉搜索树 - 力扣(Leetcode)
98. 验证二叉搜索树 - 力扣(Leetcode)
3.代码实现:
方式一:中序遍历的方式
class Solution {
//创建一个long类型的最小值,用于判断,为什么不设置为Int类型,因为整个树的数据类型都是Int,用Int的话值会被覆盖掉,而long类型覆盖了整个Int类型的范围
//为什么变量声明为static会报错,因为static只会被初始化一次,那么当case1测试完毕后,测试case2、3。。等都沿用了case1里面的值。
long pre = Long.MIN_VALUE;//记录上一个节点的值,初始值为Long的最小值
public boolean isValidBST(TreeNode root) {
if (root == null) {
return true;
}
// 访问左子树,如果左子树中任意一个节点出错就可以直接返回false,不用后续再遍历了
if (!isValidBST(root.left)) {
return false;
}
// 访问当前节点:如果当前节点小于等于中序遍历的前一个节点,说明不满足BST,返回 false;否则继续遍历。
if (root.val <= pre) {
return false;
}
pre = root.val;
// 访问右子树,到了这一步说明前面的都是true,所以这里不管是true还是false直接返回就行
return isValidBST(root.right);
}
}
方式二:递归
class Solution {
public boolean isValidBST(TreeNode root) {
return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
public boolean isValidBST(TreeNode node, long lower, long upper) {
if (node == null) {
return true;
}
if (node.val <= lower || node.val >= upper) {
return false;
}
return isValidBST(node.left, lower, node.val) && isValidBST(node.right, node.val, upper);
}
}