lotus

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

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  1846 随笔 :: 0 文章 :: 109 评论 :: 288万 阅读

1. 题目

 

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

 

考察点

 

这道题的考察点是:

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

2. 解法

背景:什么是二叉搜索树

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

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

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

 

二种解法

  • 递归 
  • 迭代

 

解法一:递归 

思路

算法的思路是这样的:

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

 

具体实现

1
2
3
4
5
6
7
8
9
10
11
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。

具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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   白露~  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
历史上的今天:
2021-04-25 Dubbo源码分析(十)同步调用与异步调用
2021-04-25 Dubbo源码分析(九)负载均衡算法
2021-04-25 Dubbo源码分析(八)集群容错机制
2021-04-25 Dubbo源码分析(七)服务目录
2021-04-25 Dubbo源码分析(六)服务引用的具体流程
2021-04-25 Dubbo源码分析(五)服务暴露的具体流程(下)
2021-04-25 Dubbo源码分析(四)服务暴露的具体流程(上)
点击右上角即可分享
微信分享提示