leecode98 验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
🔎思路:要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。(参考leecode题解)
这道题目比较容易陷入两个陷阱:
刚开始我还想使用队列层序遍历这棵树,将结果存入数组,最后判断数组是不是递增(大错特错!)
🌙(1)不能单纯的比较左节点小于中间节点,右节点大于中间节点就完事了。比如下面这棵树:
按层序遍历,我们得到节点值的数组为 [4, 2, 7, 5, 9]。数组是递增的,但是该树并不是二叉搜索树,因为根节点的右子树中的节点值小于根节点的值。
🌙(2)要解决这道题首先我们要了解二叉搜索树有什么性质可以给我们利用,由题目给出的信息我们可以知道:如果该二叉树的左子树不为空,则左子树上所有节点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
它的左右子树也为二叉搜索树。
这启示我们设计一个递归函数 helper(root, lower, upper) 来递归判断,函数表示考虑以 root 为根的子树,判断子树中所有节点的值是否都在 (l,r) 的范围内,如果root节点的值val不在(l,r) 范围内,说明不满足条件直接返回,否则我们要继续递归调用检查它的左右子树是否满足,如果都满足才说明这是一棵二叉搜索树。
那么根据二叉搜索树的性质,在递归调用左子树时,我们需要把上界 upper 改为 root.val,即调用 helper(root.left, lower, root.val),因为左子树里所有节点的值均小于它的根节点的值
。同理递归调用右子树时
,我们需要把下界 lower 改为 root.val
,即调用 helper(root.right, root.val, upper)。函数递归调用的入口为 helper(root, -inf, +inf), inf 表示一个无穷大的值。
🔎代码如下:
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);
}
}
🟢举例:
首先,我们调用 isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE),其中 root 是根节点,Long.MIN_VALUE 和 Long.MAX_VALUE 是验证范围的初始最小值和最大值。
步骤 1:
我们进入 isValidBST 方法,传入根节点 4,以及初始的范围 (Long.MIN_VALUE, Long.MAX_VALUE)。
步骤 2:
检查根节点的值 4 是否在 (Long.MIN_VALUE, Long.MAX_VALUE) 的范围内。是的,所以继续。
步骤 3:
递归验证左子树 2。我们进入 isValidBST 方法,传入节点 2,以及范围 (Long.MIN_VALUE, 4)。
步骤 4:
检查节点 2 的值 2 是否在 (Long.MIN_VALUE, 4) 的范围内。是的,所以继续。
步骤 5:
左子树为空,验证通过。
步骤 6:
递归验证右子树 6。我们进入 isValidBST 方法,传入节点 6,以及范围 (4, Long.MAX_VALUE)。
步骤 7:
检查节点 6 的值 6 是否在 (4, Long.MAX_VALUE) 的范围内。是的,所以继续。
步骤 8:
递归验证左子树 5。我们进入 isValidBST 方法,传入节点 5,以及范围 (4, 6)。
步骤 9:
检查节点 5 的值 5 是否在 (4, 6) 的范围内。是的,所以继续。
步骤 10:
左子树为空,验证通过。
步骤 11:
右子树为空,验证通过。
步骤 12:
回到节点 6,递归验证右子树完成。
步骤 13:
回到根节点 4,递归验证右子树完成。
步骤 14:
回到调用 isValidBST 的方法,所有节点验证完成,没有发现违反二叉搜索树条件的节点。
因此,根据给定的代码,这棵二叉树是二叉搜索树。