验证二叉搜索树-98

题意

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  1. 节点的左子树只包含 小于 当前节点的数。
  2. 节点的右子树只包含 大于 当前节点的数。
  3. 所有左子树和右子树自身必须也是二叉搜索树。

难度

中等

示例

示例 1:

输入:root=[2,1,3]

输出:true

示例 2:

输入:root=[5,1,4,null,null,3,6]

输出:false

解释:根节点的值是5,但是右子节点的值是4。

分析

树的本质就是递归,相信这个朴素的道理大家都能懂,二叉搜索树也不例外,我们仍然可以通过递归来检验当前二叉树是否为二叉搜索树。

观察一下题目中的条件:

  1. 节点的左子树只包含 小于 当前节点的数。
  2. 节点的右子树只包含 大于 当前节点的数。
  3. 所有左子树和右子树自身必须也是二叉搜索树。

这就把解题的思路告诉我们了:

  1. 每个节点的左子树中的最大值要小于当前节点的值
  2. 每个节点的右子树中的最小值要大于当前节点的值

也就是说,对于任意节点 n,其左子树中的所有节点的值都小于 n.val,其右子树中的所有节点的值都大于 n.val。

最后注意一个非常关键的点:空树也是二叉搜索树,这道题便能解开了。

/**

*Definitionforabinarytreenode.

*public  class  TreeNode{

*int  val;

*TreeNode  left;

*TreeNode  right;

*TreeNode(){}

*TreeNode (int  val){this.val=val;}

*TreeNode(int  val,TreeNode  left,TreeNode  right){

*this.val=val;

*this.left=left;

*this.right=right;

*}

*}

*/

class  Solution{

//主方法调用辅助方法并以最大范围作为开始

public  boolean  isValidBST(TreeNode root){

return  isValidBST(root,Long.MIN_VALUE,Long.MAX_VALUE);

}



//辅助递归方法

public  boolean  isValidBST(TreeNode  root,long lower,long upper){

//如果到达叶子节点下的空位置,则此路径上的所有节点都满足BST条件

if(root==null){

return true;

}

//如果当前节点的值不在(lower,upper)的范围内,则不是BST

if(root.val<=lower||root.val>=upper){

return  false;

}

//对左子树进行检查,更新上限为当前节点的值

//对右子树进行检查,更新下限为当前节点的值

//只有左右子树都是BST时,整棵树才是BST

return isValidBST(root.left,lower,root.val)&&isValidBST(root.right,root.val,upper);

}

}

对于最初的根节点,我们不需要对其进行任何限制,所以我们可以直接将限制设置为Long.MIN_VALUE和Long.MAX_VALUE。

假如 root 为 [5,1,4,null,null,3,6],我们来验证一下,首先构建这棵树的结构:

5

/\

14

/\

36

接下来,我们按照题解的过程一步步验证这是否是一个有效的二叉搜索树(BST):

  1. 调用 isValidBST 根节点为 5,上下界为 Long.MIN_VALUE 和 Long.MAX_VALUE。
  2. 节点 5 在上下界 Long.MIN_VALUE 和 Long.MAX_VALUE 之间,因此有效。接下来:
  3. 对左子树调用 isValidBST,上界更新为 5。
  4. 对右子树调用 isValidBST,下界更新为 5。
  5. 在节点 1 上:
  6. 节点 1 在上下界 Long.MIN_VALUE 和 5 之间,因此有效。
  7. 因为节点 1 没有子节点,所以其左右子树都是空的,对它们的递归调用将返回 true。
  8. 在节点 4 上:
  9. 节点 4 在上下界 5 和 Long.MAX_VALUE 之间,因此有效。
  10. 对左子树调用 isValidBST,上界更新为 4。
  11. 对右子树调用 isValidBST,下界更新为 4。
  12. 在节点 3 上:
  13. 节点 3 在上下界 Long.MIN_VALUE 和 4 之间,但是节点 3 应该大于所有祖先节点中在它右边的,也就是它应该大于 5。因此,它违反了 BST 的条件,返回 false。
  14. 在节点 6 上:
  15. 尽管节点 6 在上下界 4 和 Long.MAX_VALUE 之间,但我们不会到达这里,因为它的左兄弟(节点 3)已经导致了失败的结果。

综上,当遇到节点 3 的时候,它没有满足BST的条件,所以整棵树不是BST,验证方法将返回 false。

假如 root 为 [2,1,3],这棵树的结构如下:

2

/\

13

按照题解的过程验证这是否是一个有效的二叉搜索树(BST):

  1. 调用 isValidBST 根节点为 2,上下界为 Long.MIN_VALUE 和 Long.MAX_VALUE。
  2. 节点 2 在上下界 Long.MIN_VALUE 和 Long.MAX_VALUE 之间,因此有效。接下来:
  3. 对左子树调用 isValidBST,上界更新为 2。
  4. 对右子树调用 isValidBST,下界更新为 2。
  5. 在节点 1 上:
  6. 节点 1 在上下界 Long.MIN_VALUE 和 2 之间,因此有效。
  7. 节点 1 没有子节点,所以其左右子树都是空的,对它们的递归调用将返回 true。
  8. 在节点 3 上:
  9. 节点 3 在上下界 2 和 Long.MAX_VALUE 之间,因此有效。
  10. 节点 3 没有子节点,所以其左右子树都是空的,对它们的递归调用将返回 true。

由于所有节点都在各自的上下界之内,并且没有违反BST的特性,所以整棵树符合BST的定义,验证方法将返回 true。

来看一下题解效率:

为什么要用Long类型来进行限制呢?

在这个题解中,使用 Long 类型的 MIN_VALUE 和 MAX_VALUE 作为边界,是因为二叉搜索树的定义中对于任何节点来说,其左子树上的所有节点的值都要小于该节点的值,而右子树上的所有节点的值都要大于该节点的值。为了通用性,根节点的值可以是任何 Integer 类型内的值,包括 Integer.MIN_VALUE 和 Integer.MAX_VALUE。

如果我们仅使用 Integer 类型的边界来初始化,那么当根节点的值恰好是 Integer.MIN_VALUE 或 Integer.MAX_VALUE 时,我们就无法设置一个比 Integer.MIN_VALUE 更小或比 Integer.MAX_VALUE 更大的边界值了。这将导致算法不能正确地处理这些边界情况。

通过使用 Long 类型的 MIN_VALUE 和 MAX_VALUE,我们确保了即使是 Integer 范围的最小或最大值也会有有效的边界检查。这是一种编程上的预防措施,以确保算法对所有合法的 Integer 值都是健壮的。在实际情况下,对于二叉搜索树的每个节点,其值都是一个 int,但在递归检查时,我们可以用更大范围的 long 类型来避免边界条件的问题。

总结

树的本质就是递归”,相信大家都能理解。

递归是一种通过重复将问题分解为同类的子问题而解决问题的方法。递归解决问题的过程中,我们会将问题分解为更小的子问题,然后递归地解决这些子问题,最后将它们的答案组合起来得到原始问题的答案。

在树结构中,每个节点都可以被看作是一个子树的根。树中的每个节点都重复这个结构,即它有子节点,子节点下面还有子节点,依此类推,直到叶子节点(没有子节点的节点)。这种自相似的特性是递归的本质。因此,许多在树上的操作,如搜索、插入和删除,可以自然而然地用递归来实现。

力扣链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值