lotus

贵有恒何必三更眠五更起 最无益只怕一日曝十日寒

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

1. 题目

 

https://leetcode.cn/problems/validate-binary-search-tree/

 

考察点

 

这道题的考察点是:

  • 对二叉搜索树的定义和性质的理解和掌握。
  • 对递归和迭代的思想和实现的熟练度。
  • 对中序遍历的原理和应用的掌握。
  • 对边界值和特殊情况的处理能力。

2. 解法

背景:什么是二叉搜索树

二叉搜索树是一种特殊的二叉树,它的每个结点都有一个关键字,而且满足以下性质:

  • 左子树上所有结点的关键字都小于根结点的关键字。
  • 右子树上所有结点的关键字都大于根结点的关键字。
  • 左右子树也都是二叉搜索树。
  • 没有两个结点的关键字相同。

二叉搜索树可以高效地进行查找、插入和删除操作,因为它可以利用关键字的顺序信息

 

二种解法

  • 递归 
  • 迭代

 

解法一:递归 

思路

算法的思路是这样的:

  • 定义一个递归函数,接受一个节点和一个上下界作为参数,表示要检查的子树和合法的范围。
  • 如果节点为空,返回true,表示空节点是有效的。
  • 如果节点的值不在上下界内,返回false,表示节点不满足二叉搜索树的条件。
  • 递归地检查节点的左子树和右子树,左子树的上界是节点的值,右子树的下界是节点的值,如果有任何一个返回false,就返回false,否则返回true。
  • 在主函数中,调用递归函数,传入根节点和最小值和最大值作为参数。

 

具体实现

class Solution {
    public boolean isValidBST(TreeNode root) {
        return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    private 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); // 递归检查左右子树
    }
}

  

分析

这个算法的优点是简单易懂,逻辑清晰,可以正确地判断二叉搜索树的有效性。它的时间复杂度是O(n),空间复杂度是O(h),其中n是节点的个数,h是树的高度。

这个算法的缺点是需要额外的空间来存储上下界,而且对于边界值可能会有溢出的风险,比如如果节点的值是整型的最大值或最小值。另外,它没有利用二叉搜索树的中序遍历是有序的这一性质,可能会有更优化的方法。

 

解法二:迭代

思路

代码 逻辑

  • 定义一个栈,用来存储节点,模拟递归的调用栈。
  • 定义一个变量,记录前一个节点的值,初始为最小值。
  • 定义一个指针,指向当前节点,初始为根节点。
  • 当栈不为空或者指针不为空时,循环以下步骤:
    • 如果指针不为空,说明还有左子树没有遍历,将其压入栈中,然后将指针指向其左子节点,重复这一步骤,直到指针为空。
    • 如果指针为空,说明已经到达最左下的节点,弹出栈顶元素,作为当前节点,检查其是否大于前一个节点,如果不是,返回false。
    • 更新前一个节点的值为当前节点的值,然后将指针指向其右子节点,继续循环。
  • 如果循环结束,没有返回false,说明是有效的二叉搜索树,返回true。

具体实现

class Solution {
    public boolean isValidBST(TreeNode root) {
        // 定义一个栈,用来存储节点
        Stack<TreeNode> stack = new Stack<>();
        // 定义一个变量,记录前一个节点的值
        long prev = Long.MIN_VALUE;
        // 定义一个指针,指向当前节点
        TreeNode curr = root;
        // 当栈不为空或者指针不为空时,循环
        while (!stack.isEmpty() || curr != null) {
            // 如果指针不为空,将其压入栈中,然后向左移动
            while (curr != null) {
                stack.push(curr);
                curr = curr.left;
            }
            // 如果指针为空,弹出栈顶元素,作为当前节点
            curr = stack.pop();
            // 检查当前节点是否大于前一个节点
            if (curr.val <= prev) return false;
            // 更新前一个节点的值
            prev = curr.val;
            // 将指针指向当前节点的右子节点
            curr = curr.right;
        }
        // 如果循环结束,没有返回false,说明是有效的二叉搜索树,返回true
        return true;
    }
}

  

 

3. 总结  

posted on 2023-04-25 13:54  白露~  阅读(11)  评论(0编辑  收藏  举报