算法通关村——二分查找在搜索树中的应用

我们发现很多题使用前序、后序或者层次遍历都可以解决,但几乎没有中序遍历的。这是因为中序与前后序相比有不一样的特征,例如中序可以和搜索树结合在一起,但是前后序则不行
二叉搜索树是一个很简单的概念,但是想说清楚却不太容易。简单来说就是如果一棵二叉树是搜索树,则按照中序遍历其序列正好是一个递增序列。比较规范的定义是:
若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;

它的左、右子树也分别为二叉排序树。下面这两棵树一个中序序列是{3,6,9,10,14,16,19},一个是{3,6,9,10},因此都是搜索树:
在这里插入图片描述
搜索树的题目虽然也是用递归,但是与前后序有很大区别,主要是因为搜索树是有序的,就可以根据条件决定某些递归不必执行,这也称为“剪枝”

1. 二叉搜索树中搜索特定值

LeetCode 700.给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。例如:
在这里插入图片描述
你应该返回如下子树:
在这里插入图片描述
本题看起来很复杂,但是实现非常简单,递归:
如果根节点为空 root == null 或者根节点的值等于搜索值 val == root.val,返回根节点。
如果 val < root.val,进入根节点的左子树查找 searchBST(root.left, val)。
如果 val > root.val,进入根节点的右子树查找 searchBST(root.right, val)。
这里提供两种遍历方法:

 /**
     * 递归方式实现
     *
     * @param root
     * @param val
     * @return
     */
    public static TreeNode searchBST(TreeNode root, int val) {
        if (root == null || val == root.val) return root;
        return val < root.val ? searchBST(root.left,val) : searchBST(root.right,val);
    }

如果采用迭代方式,也不复杂:
如果根节点不空 root != null 且根节点不是目的节点 val != root.val。
如果 val < root.val,进入根节点的左子树查找 root = root.left。
如果 val > root.val,进入根节点的右子树查找 root = root.right。

  /**
     * 迭代实现
     *
     * @param root
     * @param val
     * @return
     */
//    public static TreeNode searchBST2(TreeNode root, int val) {
//        while (root != null && val != root.val)
//            root = val < root.val ? root.left : root.right;
//        return root;
//    }
    public static TreeNode searchBST2(TreeNode root, int val) {
        while (root != null && root.val != val) {
            root = val < root.val ? root.left : root.right;
        }
        return root;
    }

2. 验证二叉搜索树

LeetCode98.给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

示例:
示例1:
输入:root = [2,1,3]
输出:true
示例2:
输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。

我们根据题目的性质,我们可以进一步知道二叉搜索树 [中序遍历] 得到的值构成的序列一定是升序的,所以在中序遍历的时候,我们实时检查当前节点的值是否大于前一个节点的值即可。
在这里插入图片描述

    /**
     * 递归实现
     */

    static long pre = Long.MIN_VALUE;

    public static boolean isValidBST(TreeNode root) {
        if (root == null) {
            return true;
        }
        // 如果左子树下某个元素不满足要求,则退出
        if (!isValidBST(root.left)) {
            return false;
        }
        // 访问当前节点:如果当前节点小于等于中序遍历的前一个节点,说明不满足BST,返回 false;否则继续遍历。
        if (root.val <= pre) {
            return false;
        }
        pre = root.val;
        // 访问右子树
        return isValidBST(root.right);
    }

另外,除了使用递归的方法,我们还可以使用迭代法进行求解,思路与上面类似:

  public static boolean isValidBST2(TreeNode root) {
        Deque<TreeNode> stack = new LinkedList<>();
        if (root == null) {
            return true;
        }
        double pre = Integer.MIN_VALUE;
        while (!stack.isEmpty() || root != null){
            while (root != null){
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            if (root.val <= pre){
                return false;
            }
            pre = root.val;
            root = root.right;
        }
        return true;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值