二叉搜索树--验证二叉搜索树

验证二叉搜索树-力扣 98 题

解题思路:利用二叉树中序遍历的特性:遍历出来的结果是升序的即符合二叉搜索树

对于二叉树中序遍历不是太理解的,作者推荐的小白书:二叉树的初步认识_加瓦不加班的博客-CSDN博客

中序非递归实现

// 解法1. 中序遍历非递归实现 1ms
public boolean isValidBST(TreeNode root) {
    TreeNode p = root;
    LinkedList<TreeNode> stack = new LinkedList<>();
    long prev = Long.MIN_VALUE;//记录上一个值
    while (p != null || !stack.isEmpty()) {
        if (p != null) {
            stack.push(p);
            p = p.left;
        } else {
            TreeNode pop = stack.pop();
            //如果相邻两个节点相等,也不应当通过测试
            if (prev >= pop.val) {
                return false;
            }
            prev = pop.val;
            p = pop.right;
        }
    }
    return true;
}
  • 记录 prev 需要用 long,否则若测试用例中最小的节点为 Integer.MIN_VALUE 则测试会失败

  • 注意,如果相邻两个节点相等,也不应当通过测试,例如,下面的树也是不合法的

中序递归实现

方法一:

// 解法2. 中序遍历递归实现(全局变量记录 prev) 0ms
long prev = Long.MIN_VALUE;
public boolean isValidBST2(TreeNode node) {
    if (node == null) {
        return true;
    }
    boolean a = isValidBST2(node.left);
    //加上这个是为了 当发现不符合时就不再去遍历剩下的节点 如果不加if (!a) 条件,就还好继续判断剩下节点是否合法就有点多此一举
    if (!a) {
        return false;
    }
    if (prev >= node.val) {
        return false;
    }
    prev = node.val;
    return isValidBST2(node.right);
}

方法二:

// 解法3. 中序遍历递归实现(局部变量记录 prev) 0ms
public boolean isValidBST(TreeNode root) {
    if (root == null) {
        return true;
    }
    return doValid(new AtomicLong(Long.MIN_VALUE),root);
}

public boolean doValid(AtomicLong prev, TreeNode node) {
    if (node == null) {
        return true;
    }
    //左子树是否合法
    boolean a = doValid(prev, node.left);
    //值的判断
    if (prev.get() >= node.val) {
        return false;
    }
    prev.set(node.val);
     //右子树是否合法
    boolean b = doValid(prev, node.right);
    //最终两边都合法才算合法
    return a && b;
}
  • 为何不能用 Long 或 long?因为它们都是局部变量且不可变,因此每次赋值时,并不会改变其它方法调用时的 prev

  • 要么把 prev 设置为 AtomicLong,要么把 prev 设置为全局变量,而不要采用方法参数这样的局部变量

  • 上述代码并不是最有效率的,分析过程见视频讲解

上下限递归

解题思路:

  /*
         能否只判断父亲比左孩子大,比右孩子小? 答:不行的,案例2中:4的右边有个3就不符合,
         也就是说 这个思路只考虑了父与子之间的大小关系,而没有考虑到祖先与子孙之间的大小关系
    案例1:               4
                       /   \
                      2     6
                     / \
                    1   3
    */
    /*案例2:
                 4 
               /   \
              2     6 
                   / \
                  3   7 
     */
    // 解法4. 上下限递归实现 0ms
//                -∞ 4 +∞
//               /   \
//           -∞ 2  4  6 +∞
//                   / \
//                4 3 6 7 +∞
//什么叫上下限递归实现?  比如上面的4,4是根节点,所以4的上限:+∞  下限:-∞
//2的上限:4   下限:-∞    
//6的上限:+∞  下限:4   
//3的上限:6  下限:4 
//7的上限:+∞  下限:6

  /*
         能否只判断父亲比左孩子大,比右孩子小? 答:不行的,案例2中:4的右边有个3就不符合,
         也就是说 这个思路只考虑了父与子之间的大小关系,而没有考虑到祖先与子孙之间的大小关系
    案例1:               4
                       /   \
                      2     6
                     / \
                    1   3
    */
    /*案例2:
                 4 
               /   \
              2     6 
                   / \
                  3   7 
     */
    // 解法4. 上下限递归实现 0ms
//			    -∞ 4 +∞
//               /   \
//           -∞ 2  4  6 +∞
//                   / \
//                4 3 6 7 +∞
//什么叫上下限递归实现?  比如上面的4,4是根节点,所以4的上限:+∞  下限:-∞
//2的上限:4   下限:-∞    
//6的上限:+∞  下限:4   
//3的上限:6  下限:4 
//7的上限:+∞  下限:6
public boolean isValidBST(TreeNode node) {
    return doValid(node, Long.MIN_VALUE, Long.MAX_VALUE);
}

private boolean doValid(TreeNode node, long min, long max) {
    if (node == null) {
        return true;
    }
    if (node.val <= min || node.val >= max) {
        return false;
    }
    return doValid(node.left, min, node.val) && doValid(node.right, node.val, max);
}
  • 设每个节点必须在一个范围内:(min, max),不包含边界,若节点值超过这个范围,则返回 false

  • 对于 node.left 范围肯定是 (min, node.val)

  • 对于 node.right 范围肯定是 (node.val, max)

  • 一开始不知道 min,max 则取 java 中长整数的最小、最大值

  • 本质是前序遍历 + 剪枝

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值